package com.engine.salary.service.impl;

import com.cloudstore.dev.api.util.Util_DataCache;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.*;
import com.engine.salary.common.LocalDateRange;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.constant.SalaryItemConstant;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.datacollection.AddUpSituation;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.salaryarchive.bo.SalaryArchiveBO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveDataDTO;
import com.engine.salary.entity.salaryarchive.dto.SalaryArchiveListDTO;
import com.engine.salary.entity.salaryarchive.param.*;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveDimissionPO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveItemPO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchivePO;
import com.engine.salary.entity.salaryarchive.po.SalaryArchiveTaxAgentPO;
import com.engine.salary.entity.salaryitem.po.SalaryItemPO;
import com.engine.salary.entity.taxagent.dto.TaxAgentEmployeeDTO;
import com.engine.salary.entity.taxagent.dto.TaxAgentManageRangeEmployeeDTO;
import com.engine.salary.entity.taxagent.po.TaxAgentEmpChangePO;
import com.engine.salary.entity.taxagent.po.TaxAgentPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.datacollection.UseEmployeeTypeEnum;
import com.engine.salary.enums.salaryarchive.*;
import com.engine.salary.enums.taxagent.TaxAgentEmpChangeModuleEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.archive.SalaryArchiveItemMapper;
import com.engine.salary.mapper.archive.SalaryArchiveMapper;
import com.engine.salary.service.*;
import com.engine.salary.sys.constant.SalarySysConstant;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.sys.entity.vo.OrderRuleVO;
import com.engine.salary.sys.enums.OpenEnum;
import com.engine.salary.sys.enums.SalaryAcctEmployeeRuleEnum;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.SalaryDateUtil;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.excel.ExcelParseHelper;
import com.engine.salary.util.excel.ExcelSupport;
import com.engine.salary.util.excel.ExcelUtilPlus;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.BeanUtils;
import org.springframework.transaction.annotation.Transactional;
import weaver.file.ImageFileManager;
import weaver.general.Util;
import weaver.hrm.User;

import java.io.InputStream;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.engine.salary.util.excel.ExcelSupport.EXCEL_TYPE_XLSX;

/**
 * 薪资档案
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class SalaryArchiveServiceImpl extends Service implements SalaryArchiveService {

    private SalaryArchiveBiz salaryArchiveMapper = new SalaryArchiveBiz();
    private SalaryArchiveItemBiz salaryArchiveItemMapper = new SalaryArchiveItemBiz();
    private SalaryArchiveTaxAgentBiz salaryArchiveTaxAgentMapper = new SalaryArchiveTaxAgentBiz();
    private SalaryArchiveDimissionBiz salaryArchiveDimissionMapper = new SalaryArchiveDimissionBiz();
    private SalaryItemBiz salaryItemMapper = new SalaryItemBiz();


    private TaxAgentService getTaxAgentService(User user) {
        return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }

    private SalaryArchiveMapper getSalaryArchiveMapper() {
        return MapperProxyFactory.getProxy(SalaryArchiveMapper.class);
    }

    private SalaryArchiveItemMapper getSalaryArchiveItemMapper() {
        return MapperProxyFactory.getProxy(SalaryArchiveItemMapper.class);
    }

    private SalaryAcctEmployeeService getSalaryAcctEmployeeService(User user) {
        return ServiceUtil.getService(SalaryAcctEmployeeServiceImpl.class, user);
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    private TaxAgentEmpChangeService getTaxAgentEmpChangeService(User user) {
        return ServiceUtil.getService(TaxAgentEmpChangeServiceImpl.class, user);
    }

    private SalaryArchiveItemService getSalaryArchiveItemService(User user) {
        return ServiceUtil.getService(SalaryArchiveItemServiceImpl.class, user);
    }

    public SalarySobService getSalarySobService(User user) {
        return ServiceUtil.getService(SalarySobServiceImpl.class, user);
    }

    @Override
    public SalaryArchivePO getById(Long salaryArchiveId) {
        return salaryArchiveMapper.getById(salaryArchiveId);
    }

    @Override
    public List<SalaryArchivePO> listSome(SalaryArchivePO po) {
        Collection<Long> ids = po.getIds();
        if (CollectionUtils.isNotEmpty(ids)) {
            List<SalaryArchivePO> list = new ArrayList<>();
            List<List<Long>> partition = Lists.partition((List<Long>) ids, 1000);
            partition.forEach(idss -> {
                po.setIds(idss);
                list.addAll(getSalaryArchiveMapper().listSome(po));
            });
            return list;
        }

        Collection<Long> employeeIds = po.getEmployeeIds();
        if (CollectionUtils.isNotEmpty(employeeIds)) {
            List<SalaryArchivePO> list = new ArrayList<>();
            List<List<Long>> partition = Lists.partition((List<Long>) employeeIds, 1000);
            partition.forEach(emps -> {
                po.setEmployeeIds(emps);
                list.addAll(getSalaryArchiveMapper().listSome(po));
            });
            return list;
        }

        // 获取薪资档案数据
        return getSalaryArchiveMapper().listSome(po);
    }

    @Override
    public List<SalaryArchiveListDTO> getSalaryArchiveList(SalaryArchiveQueryParam queryParam) {
        if (queryParam.isExtSalaryArchiveList()) {
            return getSalaryArchiveMapper().listExtSalaryArchive(queryParam);
        }
        if (StringUtils.isNotBlank(queryParam.getPayStartDateStartDateStr())) {
            queryParam.setPayStartDateStartDate(SalaryDateUtil.stringToDate(queryParam.getPayStartDateStartDateStr()));
        }
        if (Objects.nonNull(queryParam.getPayStartDateEndDateStr())) {
            queryParam.setPayStartDateEndDate(SalaryDateUtil.stringToDate(queryParam.getPayStartDateEndDateStr()));
        }

        if (StringUtils.isNotBlank(queryParam.getPayEndDateStartDateStr())) {
            queryParam.setPayEndDateStartDate(SalaryDateUtil.stringToDate(queryParam.getPayEndDateStartDateStr()));
        }
        if (Objects.nonNull(queryParam.getPayEndDateEndDateStr())) {
            queryParam.setPayEndDateEndDate(SalaryDateUtil.stringToDate(queryParam.getPayEndDateEndDateStr()));
        }

        List<SalaryArchiveListDTO> list = getSalaryArchiveMapper().list(queryParam);
        return SalaryI18nUtil.i18nList(list);
    }

    @Override
    public PageInfo<SalaryArchiveListDTO> listPage(SalaryArchiveQueryParam queryParam) {
        long currentEmployeeId = user.getUID();

        /**
         * 异步处理档案数据
         */
        String handleable = Util.null2String(Util_DataCache.getObjVal("salaryArchiveHandleable"));
        if ((StringUtils.isBlank(handleable) || OpenEnum.OPEN.getValue().equals(handleable)) && !queryParam.isExtSalaryArchiveList()) {
            new Thread() {
                public void run() {
                    Util_DataCache.setObjVal("salaryArchiveHandleable", "0");
                    // 1.历史数据处理
                    handleHistory(currentEmployeeId);
                    // 2.待停薪自动处理
                    handleSuspendData(currentEmployeeId);
                    // 3.增量数据处理
//                    handleChangeData(currentEmployeeId);
                    Util_DataCache.setObjVal("salaryArchiveHandleable", "1");
                }
            }.start();
        }


        Boolean needAuth = getTaxAgentService(user).isNeedAuth(currentEmployeeId);

        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);
        List<SalaryArchiveListDTO> list = getSalaryArchiveList(queryParam);
        list = list.stream()
                //过滤档案状态
                .filter(dto -> {
                    if (StringUtils.isNotBlank(queryParam.getArchiveStatus())) {
                        return StringUtils.equals(queryParam.getArchiveStatus(), dto.getArchiveStatus());
                    }
                    return true;
                })
                .collect(Collectors.toList());

        if (needAuth) {
            Boolean adminEnable = getTaxAgentService(user).isAdminEnable(currentEmployeeId);
            //不是管理员看不到数据，返回空
            if (!adminEnable) {
                PageInfo<SalaryArchiveListDTO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), SalaryArchiveListDTO.class);
                return pageInfo;
            }
            // 获取作为管理员的所有个税扣缴义务人列表
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId);
            Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);
            list = list.stream().filter(dto -> taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList());
        }
        PageInfo<SalaryArchiveListDTO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), SalaryArchiveListDTO.class);
        pageInfo.setTotal(list.size());
        pageInfo.setList(SalaryPageUtil.subList(queryParam.getCurrent(), queryParam.getPageSize(), list));
        return pageInfo;
    }

    /**
     * 1、员工的人事状态属性从在职变成非在职，且在【发薪员工】里，则自动进入【待停薪】；
     * 2、若维护了最后发薪日大于当前日期，会自动清除该员工的待办数据；
     * 3、个税扣缴义务人发生调整的发薪员工自动进入【待停薪】；
     * <p>
     * 1.【发薪员工】中，员工的人事状态属性从在职变成非在职，则自动进入【待停薪】；
     * 2.【定薪员工】中，如果维护了最后发薪日且大于今天的，自动清除待停薪，如果小于等于今天的则自动进入待停薪
     *
     * @param currentEmployeeId
     */
    @Transactional(rollbackFor = Exception.class)
    public void handleSuspendData(Long currentEmployeeId) {
        List<String> personnelStatuss = new ArrayList<String>() {{
            add("4");
            add("5");
            add("6");
        }};

        // 1.定薪员工非在职
        if (CollectionUtils.isNotEmpty(personnelStatuss)) {
            SalaryArchiveQueryParam queryParam = SalaryArchiveQueryParam.builder()
                    // 离职
                    .personnelStatuss(personnelStatuss)
                    // 定薪列表
                    .runStatusList(Collections.singletonList(SalaryArchiveStatusEnum.FIXED.getValue()))
                    .build();
            List<SalaryArchiveListDTO> noNormalList = getSalaryArchiveList(queryParam);
            if (CollectionUtils.isNotEmpty(noNormalList)) {
                List<Long> idList = noNormalList.stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList());
                List<List<Long>> partition = Lists.partition(idList, 999);
                partition.forEach(part ->
                        getSalaryArchiveMapper().updateRunStatusByIdsAndPayEndDate(SalaryArchivePO.builder().ids(part).runStatus(SalaryArchiveStatusEnum.SUSPEND.getValue()).build())
                );
            }
        }
        Date today = new Date();
        // 2.定薪员工维护了最后发薪日,且大于今天的，自动清除待停薪
        getSalaryArchiveMapper().updateFixed(SalaryArchivePO.builder().payEndDate(today).build());
        // 3.定薪员工维护了最后发薪日，且小于等于今天的，自动进入待停薪
        getSalaryArchiveMapper().updateSuspend(SalaryArchivePO.builder().payEndDate(today).build());
    }


    /**
     * 处理增量数据
     *
     * @param currentEmployeeId
     */
    public void handleChangeData(Long currentEmployeeId) {

        // 所有增量人员列表
        List<TaxAgentEmpChangePO> taxAgentEmpChangeList = getTaxAgentEmpChangeService(user).listAllByModule(TaxAgentEmpChangeModuleEnum.SALARY_ARCHIVE);
        if (CollectionUtils.isEmpty(taxAgentEmpChangeList)) {
            return;
        }
        // 当前可以管辖的人员
        Collection<TaxAgentPO> taxAgentList = new ArrayList<>();
        if (currentEmployeeId != 1L) {
            taxAgentList = getTaxAgentService(user).listAllTaxAgents(currentEmployeeId);
            Collection<TaxAgentPO> finalTaxAgentList = taxAgentList;
            taxAgentEmpChangeList = taxAgentEmpChangeList.stream().filter(f -> finalTaxAgentList.stream().anyMatch(e -> e.getId().equals(f.getTaxAgentId()))).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgentEmpChangeList)) {
                return;
            }
        }
        // 所有档案数据
        List<SalaryArchivePO> salaryArchiveList = getSalaryArchiveMapper().listAll();
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = salaryItemMapper.getCanAdjustSalaryItems();
        Collection<Long> salaryItemIds = salaryItems.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        // 获取薪资档案所对应的当前生效的薪资项目数据
        List<SalaryArchiveItemPO> salaryArchiveItemList = getCurrentEffectiveItemList(Lists.newArrayList(), salaryItemIds);
        /** 增量处理 start ***/
        SalaryArchiveBO.ChangeData changeData = SalaryArchiveBO.buildChangeData(taxAgentEmpChangeList, salaryArchiveList, salaryArchiveItemList, currentEmployeeId);
        // 批量修改薪资档案
        if (CollectionUtils.isNotEmpty(changeData.getSalaryArchiveUpdateTodoList())) {
            salaryArchiveMapper.batchUpdate(changeData.getSalaryArchiveUpdateTodoList());
        }
        // 批量新增薪资档案
        if (CollectionUtils.isNotEmpty(changeData.getSalaryArchiveAddTodoList())) {
            salaryArchiveMapper.batchInsert(changeData.getSalaryArchiveAddTodoList());
        }
        // 落库处理薪资项目
        if (CollectionUtils.isNotEmpty(changeData.getSalaryArchiveItemAddTodos())) {
            salaryArchiveItemMapper.batchInsert(changeData.getSalaryArchiveItemAddTodos(), user);
        }
        // 删除增量数据
        if (CollectionUtils.isNotEmpty(changeData.getChangeIds())) {
            getTaxAgentEmpChangeService(user).deleleByIds(changeData.getChangeIds());
        }
        /** 增量处理 end ***/

    }

    @Override
    public void deleteSalaryArchive(Collection<Long> salaryArchiveIds) {
        if (CollectionUtils.isEmpty(salaryArchiveIds)) {
            throw new SalaryRunTimeException("薪资档案参数为空!");
        }
        SalarySysConfPO canDelete = getSalarySysConfService(user).getOneByCode(SalarySysConstant.SALARY_ARCHIVE_DELETE);
        if (Objects.isNull(canDelete) || StringUtils.equals(canDelete.getConfValue(), "0")) {
            throw new SalaryRunTimeException("不允许删除薪资档案，请先开启删除档案规则配置！");
        }
        List<SalaryArchivePO> salaryArchiveList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(salaryArchiveIds).build());

        //查询当前登录人员管理的个税扣缴义务人
        List<Long> canDeleteTaxAgentIds = getTaxAgentService(user).listAllTaxAgentsAsAdmin((long) user.getUID())
                .stream().map(TaxAgentPO::getId).collect(Collectors.toList());
        boolean err = salaryArchiveList.stream().anyMatch(po -> !canDeleteTaxAgentIds.contains(po.getTaxAgentId()));
        if (CollectionUtils.isEmpty(salaryArchiveList) || err) {
            throw new SalaryRunTimeException("薪资档案不存在，或没有权限删除该薪资档案！");
        }
        Optional<SalaryArchivePO> fixedList = salaryArchiveList.stream().filter(archive -> !StringUtils.equals(archive.getRunStatus(), SalaryArchiveStatusEnum.PENDING.getValue())
                && !StringUtils.equals(archive.getRunStatus(), SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue())).findFirst();
        if (fixedList.isPresent()) {
            throw new SalaryRunTimeException("发薪员工、待停薪员工、停薪_来自待停薪，无法删除薪资档案！");
        }
        List<Long> deleteIds = salaryArchiveList.stream().map(SalaryArchivePO::getId).collect(Collectors.toList());
        // 删除薪资档案及档案项目
        if (CollectionUtils.isNotEmpty(deleteIds)) {
            getSalaryArchiveMapper().deleteByIds(deleteIds);
            getSalaryArchiveItemMapper().deleteBySalaryArchiveId(deleteIds);
        }
    }


    @Override
    public List<SalaryArchiveListDTO> list(SalaryArchiveQueryParam queryParam) {
        long currentEmployeeId = user.getUID();

        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

        Boolean needAuth = getTaxAgentService(user).isNeedAuth(currentEmployeeId);
        if (needAuth) {

            Boolean adminEnable = getTaxAgentService(user).isAdminEnable(currentEmployeeId);
            //不是管理员看不到数据，返回空
            if (!adminEnable) {
                return new ArrayList<>();
            }

            //获取管理的人员范围
            List<TaxAgentEmployeeDTO> taxAgentEmployeeDTOS = getTaxAgentService(user).listTaxAgentAndEmployee(currentEmployeeId);
            Set<Long> employeeId = SalaryEntityUtil.properties(taxAgentEmployeeDTOS, TaxAgentEmployeeDTO::getEmployeeId);

            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId);
            Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);

            //获取所有薪资档案
            List<SalaryArchiveListDTO> list = getSalaryArchiveList(queryParam);
            List<SalaryArchiveListDTO> finalAllArchive = list.stream().filter(dto -> employeeId.contains(dto.getEmployeeId()) && taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList());

            return finalAllArchive;
        } else {
            return getSalaryArchiveList(queryParam);
        }
    }

    /**
     * 获取薪资档案对应的当前生效的薪资项目
     *
     * @param salaryArchivesIds
     * @return
     */
    @Override
    public List<SalaryArchiveItemPO> getCurrentEffectiveItemList(Collection<Long> salaryArchivesIds, Collection<Long> salaryItemIds) {
        if (CollectionUtils.isEmpty(salaryItemIds)) {
            return Collections.EMPTY_LIST;
        }
        List<SalaryArchiveItemPO> salaryArchiveItems = salaryArchiveItemMapper.getCurrentEffectiveItemList(SalaryArchiveItemQueryParam.builder().salaryArchivesIds(salaryArchivesIds).salaryItemIds(salaryItemIds).effectiveTime(new Date()).build());
        return salaryArchiveItems.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getSalaryArchiveId() + "-" + f.getSalaryItemId()))), ArrayList::new));
    }

    /**
     * 获取薪资档案对应的当前生效的个税扣缴义务人
     *
     * @param salaryArchivesIds
     * @return
     */
    @Override
    public List<SalaryArchiveTaxAgentPO> getCurrentEffectiveTaxAgentList(Collection<Long> salaryArchivesIds) {
        if (CollectionUtils.isEmpty(salaryArchivesIds)) {
            return Collections.EMPTY_LIST;
        }
        List<SalaryArchiveTaxAgentPO> salaryArchiveTaxAgents = salaryArchiveTaxAgentMapper.listByParam(SalaryArchiveTaxAgentQueryParam.builder().salaryArchivesIds(salaryArchivesIds).effectiveTime(new Date()).build());

        return salaryArchiveTaxAgents.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SalaryArchiveTaxAgentPO::getSalaryArchiveId))), ArrayList::new));
    }

    /**
     * 构建薪资档案数据
     *
     * @param salaryArchives
     * @param taxAgentLists
     * @param salaryItems
     * @param isPage
     * @return
     */
    @Override
    public List<Map<String, Object>> buildSalaryArchiveData(Collection<SalaryArchiveListDTO> salaryArchives, Collection<TaxAgentPO> taxAgentLists, List<SalaryItemPO> salaryItems, Boolean isPage) {
        // 分页用于表格展示，否则用于导出
        Collection<Long> ids = isPage ? salaryArchives.stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList()) : CollectionUtils.emptyCollection();

        List<Long> salaryItemIds = salaryItems.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        // 1.获取薪资档案所对应的当前生效的薪资项目数据
        List<SalaryArchiveItemPO> salaryArchiveItemList = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(ids) && CollectionUtils.isNotEmpty(salaryItemIds) || !isPage) {
            salaryArchiveItemList = getCurrentEffectiveItemList(ids, salaryItemIds);
        }
        List<SalaryArchiveItemPO> finalSalaryArchiveItemList = salaryArchiveItemList;
        List<Map<String, Object>> salaryArchiveItemData = salaryArchives.stream().map(m -> {
            Map<String, Object> map = Maps.newHashMap();
            map.put("salaryArchiveId", m.getId());
            map.put("archiveStatus", m.getArchiveStatus());
            List<SalaryArchiveItemPO> salaryArchiveItemValuelList = finalSalaryArchiveItemList.stream().filter(i -> i.getSalaryArchiveId().equals(m.getId())).collect(Collectors.toList());
            salaryArchiveItemValuelList.forEach(i -> {
                map.put(i.getSalaryItemId() + SalaryItemConstant.DYNAMIC_SUFFIX, i.getItemValue());
            });
            return map;
        }).collect(Collectors.toList());
        //2.获取薪资档案所对应的当前生效的个税扣缴义务人列表
//        List<SalaryArchiveTaxAgentPO> taxAgentList = getCurrentEffectiveTaxAgentList(ids);
//        List<Map<String, Object>> taxAgentData = taxAgentList.stream().map(m -> {
//            Map<String, Object> map = Maps.newHashMap();
//            map.put("salaryArchiveId", m.getSalaryArchiveId());
//            map.put("taxAgentId", m.getTaxAgentId());
//            Optional<TaxAgentPO> optional = taxAgentLists.stream().filter(f -> f.getId().equals(m.getTaxAgentId())).findFirst();
//            map.put("taxAgentName", optional.isPresent() ? optional.get().getName() : "");
//            map.put("taxAgentEffectiveTime", m.getEffectiveTime());
//            return map;
//        }).collect(Collectors.toList());
        Map<Long, TaxAgentPO> longTaxAgentPOMap = SalaryEntityUtil.convert2Map(taxAgentLists, TaxAgentPO::getId);
        // 3.组装数据
        List<Map<String, Object>> listMaps = new ArrayList<>();
        salaryArchives.forEach(e -> {
            e.setEmployeeStatus(NumberUtils.isCreatable(e.getEmployeeStatus()) ? UserStatusEnum.getDefaultLabelByValue(Integer.parseInt(e.getEmployeeStatus())) : "");

            Map<String, Object> map = new LinkedHashMap<>();
            map.put("id", e.getId());
            map.put("username", e.getUsername());
            map.put("employeeId", e.getEmployeeId());

//            Optional<Map<String, Object>> optionalTaxAgent = taxAgentData.stream().filter(f -> f.get("salaryArchiveId").toString().equals(e.getId().toString())).findFirst();
            TaxAgentPO taxAgentPO = longTaxAgentPOMap.get(e.getTaxAgentId());
            map.put("taxAgentName", Optional.ofNullable(taxAgentPO).map(TaxAgentPO::getName).orElse(""));
            map.put("taxAgentId", Optional.ofNullable(taxAgentPO).map(TaxAgentPO::getId).orElse(0L));
//            map.put("taxAgentEffectiveTime", optionalTaxAgent.isPresent() ? optionalTaxAgent.get().get("taxAgentEffectiveTime") : "");

            map.put("subcompanyName", e.getSubcompanyName());
            map.put("departmentName", e.getDepartmentName());
            map.put("mobile", e.getMobile());
            map.put("workcode", e.getWorkcode());
            map.put("employeeStatus", e.getEmployeeStatus());
            map.put("payStartDate", SalaryDateUtil.getFormatLocalDate(e.getPayStartDate()));
            map.put("payEndDate", SalaryDateUtil.getFormatLocalDate(e.getPayEndDate()));
            map.put("companystartdate", e.getCompanystartdate());
            map.put("dismissdate", e.getDismissdate());

            // 薪资项目动态
            Optional<Map<String, Object>> optionalItem = salaryArchiveItemData.stream().filter(f -> f.get("salaryArchiveId").toString().equals(e.getId().toString())).findFirst();
            optionalItem.ifPresent(map::putAll);

            listMaps.add(map);
        });
        return listMaps;
    }

    @Override
    public XSSFWorkbook exportList(SalaryArchiveQueryParam queryParam) {
        long employeeId = user.getUID();

        // 1.工作簿名称
        String sheetName = SalaryI18nUtil.getI18nLabel(85368, "薪资档案");
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = salaryItemMapper.getCanAdjustSalaryItems();
        String[] header = {SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人"),
                SalaryI18nUtil.getI18nLabel(86185, "部门"),
                SalaryI18nUtil.getI18nLabel(86176, "工号"),
                SalaryI18nUtil.getI18nLabel(86186, "手机号"),
                SalaryI18nUtil.getI18nLabel(15890, "员工状态"),
                SalaryI18nUtil.getI18nLabel(91075, "起始发薪日期"),
                SalaryI18nUtil.getI18nLabel(91075, "最后发薪日期")};
        // 2.表头
        List<Object> headerList = new ArrayList<>(Arrays.asList(header));
        for (SalaryItemPO salaryItem : salaryItems) {
            headerList.add(salaryItem.getName());
        }

        // 获取所有个税扣缴义务人
        Collection<TaxAgentPO> taxAgentList = getTaxAgentService(user).listAll();
        //获取管理的人员范围
        List<TaxAgentManageRangeEmployeeDTO> taxAgentEmployeeDTOS = getTaxAgentService(user).listTaxAgentAndEmployeeTree(employeeId);
        Map<Long, List<TaxAgentManageRangeEmployeeDTO.TaxAgentEmployee>> taxAgentEmployeesMap = SalaryEntityUtil.convert2Map(taxAgentEmployeeDTOS, TaxAgentManageRangeEmployeeDTO::getTaxAgentId, TaxAgentManageRangeEmployeeDTO::getEmployeeList);


        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

        Collection<SalaryArchiveListDTO> salaryArchives = getSalaryArchiveList(queryParam);

        //分权
        Boolean needAuth = getTaxAgentService(user).isNeedAuth(employeeId);
        if (needAuth) {
            Boolean adminEnable = getTaxAgentService(user).isAdminEnable(employeeId);
            if (!adminEnable) {
                salaryArchives = new ArrayList<>();
            } else {

                Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin((long) user.getUID());
                Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);

                //获取管理扣缴单位薪资档案
                salaryArchives = salaryArchives.stream().filter(dto -> taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList());

                //过滤档案状态
                if (StringUtils.isNotBlank(queryParam.getArchiveStatus())) {
                    //过滤档案状态
                    salaryArchives = salaryArchives.stream().filter(dto -> StringUtils.equals(queryParam.getArchiveStatus(), dto.getArchiveStatus())).collect(Collectors.toList());
                }
            }
        }

        List<Map<String, Object>> listMaps = buildSalaryArchiveData(salaryArchives, taxAgentList, salaryItems, Boolean.FALSE);
        // 组装数据
        List<List<Object>> rows = new ArrayList<>();
        rows.add(headerList);
        listMaps.forEach(e -> {
            List<Object> row = new ArrayList<>();
            row.add(Util.null2String(e.get("username")));
            row.add(Util.null2String(e.get("taxAgentName")));
            row.add(Util.null2String(e.get("departmentName")));
            row.add(Util.null2String(e.get("workcode")));
            row.add(Util.null2String(e.get("mobile")));
            row.add(Util.null2String(e.get("employeeStatus")));
            row.add(Util.null2String(e.get("payStartDate")));
            row.add(Util.null2String(e.get("payEndDate")));
            // 薪资项目数据
            for (SalaryItemPO salaryItem : salaryItems) {
                row.add(e.containsKey(salaryItem.getId() + SalaryItemConstant.DYNAMIC_SUFFIX) ? (e.get(salaryItem.getId() + SalaryItemConstant.DYNAMIC_SUFFIX) == null ? "" : e.get(salaryItem.getId() + SalaryItemConstant.DYNAMIC_SUFFIX).toString()) : "");
            }
            rows.add(row);
        });
        // 3.表数据

//        return ExcelUtil.genWorkbookV2(rows, sheetName);

        // 记录日志
        String statusStr = StringUtils.join(queryParam.getRunStatusList().stream().map(status -> SalaryArchiveStatusEnum.parseByValue(status).getDefaultLabel()).collect(Collectors.toList()), ",");
        String name = SalaryI18nUtil.getI18nLabel(0, "导出");
        LoggerContext<AddUpSituation> loggerContext = new LoggerContext<>();
        loggerContext.setTargetName(SalaryI18nUtil.getI18nLabel(0, "薪资档案 ") + statusStr);
        loggerContext.setOperateType(OperateTypeEnum.EXCEL_EXPORT.getValue());
        loggerContext.setOperateTypeName(name);
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "薪资档案") + "-" + name);
        loggerContext.setUser(user);
        SalaryElogConfig.salaryArchiveLoggerTemplate.write(loggerContext);
        return ExcelUtilPlus.genWorkbookV2(rows, sheetName);
    }


    @Override
    public String savePaySet(SalaryArchiveSetPaySaveParam saveParam) {
        long currentEmployeeId = user.getUID();
        if (saveParam.getStatus() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109201, "状态不能为空"));
        }
        Boolean enableStatus = saveParam.getStatus().equals(SalaryArchiveStatusEnum.PENDING)
                || saveParam.getStatus().equals(SalaryArchiveStatusEnum.FIXED)
                || saveParam.getStatus().equals(SalaryArchiveStatusEnum.SUSPEND);
        if (!enableStatus) {
            return StringUtils.EMPTY;
        }
        if (saveParam.getSalaryArchiveId() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100425, "薪资档案id不能为空"));
        }
        SalaryArchivePO salaryArchive = getById(saveParam.getSalaryArchiveId());
        if (salaryArchive == null) {
            throw new SalaryRunTimeException(String.format(SalaryI18nUtil.getI18nLabel(100463, "薪资档案不存在") + "[id:%s]", saveParam.getSalaryArchiveId()));
        }
        SalaryArchivePO oldSalaryArchive = new SalaryArchivePO();
        BeanUtils.copyProperties(salaryArchive, oldSalaryArchive);
        List<SalaryArchivePO> oldList = Collections.singletonList(oldSalaryArchive);
        // 收入所得项目
//        boolean checkIncomeCategory = saveParam.getIncomeCategory() == null || StringUtils.isEmpty(SalaryArchiveBO.getIncomeCategoryByValue(saveParam.getIncomeCategory()));
//        if (checkIncomeCategory) {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(122085, "收入所得项目不能为空或不存在"));
//        } else {
//            salaryArchive.setIncomeCategory(saveParam.getIncomeCategory());
//        }
        // 薪资账套
//        if (CollectionUtils.isEmpty(saveParam.getSalarySobIds())) {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(122217, "薪资账套不能为空"));
//        }

        // 待定薪
        if (saveParam.getStatus().equals(SalaryArchiveStatusEnum.PENDING)) {
            if (saveParam.getPayStartDate() == null) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109202, "起始发薪日期不能为空"));
            }
            // 起薪日期：新人入职默认为：入职日期;返聘人员默认为：返聘开始日期;调整个税扣缴义务人：不默认日期
            salaryArchive.setPayStartDate(saveParam.getPayStartDate());
            if (saveParam.getPayEndDate() != null) {
                if (saveParam.getPayStartDate().after(saveParam.getPayEndDate())) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109214, "起始发薪日期不可晚于最后发薪日"));
                }
            }
            salaryArchive.setPayEndDate(saveParam.getPayEndDate());
            // 处理薪资项目
            if (CollectionUtils.isNotEmpty(saveParam.getSalaryArchiveItems())) {
                // 获取所有可被引用的薪资项目
                List<SalaryItemPO> salaryItems = getSalaryArchiveItemService(user).getCanAdjustSalaryItems();
                Collection<Long> salaryItemIds = salaryItems.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
                // 待处理薪资项目
                List<SalaryArchiveItemDetailSaveParam> salaryArchiveItems = saveParam.getSalaryArchiveItems().stream().filter(e -> salaryItemIds.contains(e.getSalaryItemId())).collect(Collectors.toList());
                List<Long> salaryItemExistIds = salaryArchiveItems.stream().map(SalaryArchiveItemDetailSaveParam::getSalaryItemId).collect(Collectors.toList());
                // 获取薪资档案所对应的当前生效的薪资项目数据
                List<SalaryArchiveItemPO> salaryArchiveItemCurrentList = getSalaryArchiveItemService(user).getCurrentEffectiveItemList(Collections.singletonList(saveParam.getSalaryArchiveId()), salaryItemExistIds);
                List<SalaryArchiveItemPO> salaryArchiveItemAddTodos = Lists.newArrayList();
                List<Long> salaryArchiveItemDelTodoIds = Lists.newArrayList();
                Date now = new Date();
                salaryArchiveItems.forEach(f -> {
                    Optional<SalaryItemPO> optional = salaryItems.stream().filter(i -> i.getId().equals(f.getSalaryItemId())).findFirst();
                    if (optional.isPresent()) {
                        SalaryItemPO salaryItemPO = optional.get();
                        boolean isNotNumber = salaryItemPO.getDataType().equals(SalaryArchiveFieldTypeEnum.NUMBER.getValue()) && StringUtils.isNotEmpty(f.getAdjustValue()) && !Pattern.matches(SalaryEntityUtil.NUMBER_REGEX, f.getAdjustValue());
                        if (isNotNumber) {
                            throw new SalaryRunTimeException(salaryItemPO.getName() + ":" + SalaryI18nUtil.getI18nLabel(100581, "请输入数字"));
                        }
                    }
                    Optional<SalaryArchiveItemPO> optionalSAI = salaryArchiveItemCurrentList.stream().filter(c ->
                            c.getSalaryArchiveId().equals(saveParam.getSalaryArchiveId()) && c.getSalaryItemId().equals(f.getSalaryItemId())
                    ).findFirst();
                    if (StringUtils.isNotEmpty(f.getAdjustValue())) {
                        salaryArchiveItemAddTodos.add(SalaryArchiveItemPO.builder()
                                .id(IdGenerator.generate())
                                .salaryArchiveId(salaryArchive.getId())
                                .employeeId(salaryArchive.getEmployeeId())
                                .effectiveTime(saveParam.getPayStartDate())
                                .adjustReason(SalaryArchiveItemAdjustReasonEnum.INIT.getValue())
                                .salaryItemId(f.getSalaryItemId())
                                .itemValue(f.getAdjustValue())
                                .description("")
                                .operator(currentEmployeeId)
                                .operateTime(now)
                                .createTime(now)
                                .updateTime(now)
                                .creator(currentEmployeeId)
                                .deleteType(NumberUtils.INTEGER_ZERO)
                                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                                .build());
                    }
                    optionalSAI.ifPresent(salaryArchiveItemPO -> salaryArchiveItemDelTodoIds.add(salaryArchiveItemPO.getId()));
                });
                // 落库处理薪资档案项目数据
                if (CollectionUtils.isNotEmpty(salaryArchiveItemAddTodos)) {
                    salaryArchiveItemMapper.batchInsert(salaryArchiveItemAddTodos, user);
                }
                if (CollectionUtils.isNotEmpty(salaryArchiveItemDelTodoIds)) {
                    salaryArchiveItemMapper.deleteBatchIds(salaryArchiveItemDelTodoIds);
                }
            }
            // 定薪
        } else if (saveParam.getStatus().equals(SalaryArchiveStatusEnum.FIXED)) {
            if (saveParam.getPayStartDate() == null) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109202, "起始发薪日期不能为空"));
            }
            salaryArchive.setPayStartDate(saveParam.getPayStartDate());
            if (saveParam.getPayEndDate() != null) {
                if (saveParam.getPayStartDate().after(saveParam.getPayEndDate())) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109214, "起始发薪日期不可晚于最后发薪日"));
                }
            }
            salaryArchive.setPayEndDate(saveParam.getPayEndDate());
            //如果是非系统人员，需要将起始发薪日期初始化
            if (Objects.equals(salaryArchive.getEmployeeType(), 1)) {
                salaryArchive.setRunStatus(SalaryArchiveStatusEnum.FIXED.getValue());
            }
            // 待停薪
        } else if (saveParam.getStatus().equals(SalaryArchiveStatusEnum.SUSPEND)) {
            if (saveParam.getPayEndDate() == null) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109203, "最后发薪日期不能为空"));
            }
            if (saveParam.getPayStartDate().after(saveParam.getPayEndDate())) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109214, "起始发薪日期不可晚于最后发薪日"));
            }
            salaryArchive.setPayEndDate(saveParam.getPayEndDate());
        }
        salaryArchive.setUpdateTime(new Date());
        getSalaryArchiveMapper().update(salaryArchive);

//        List<SalarySobPO> salarySobList = getSalarySobList(currentEmployeeId, currentTenantKey);
//        List<Long> salarySobIds = salarySobList.stream().map(SalarySobPO::getId).filter(id -> saveParam.getSalarySobIds().contains(id)).collect(Collectors.toList());
//        List<SalaryArchiveSobPO> salaryArchiveSobSaveList = SalaryArchiveBO.buildSalaryArchiveSob(salaryArchive.getId(), salarySobIds, LocalDateTime.now());
//        this.salaryArchiveSobService.saveBatchBySalaryArchiveIdsAndSaves(Collections.singletonList(salaryArchive.getId()), salaryArchiveSobSaveList, currentTenantKey);

        // 记录日志
        List<SalaryArchivePO> newList = Collections.singletonList(this.getById(salaryArchive.getId()));
        String operatedesc = SalaryI18nUtil.getI18nLabel(0, "发薪设置");
        recordLog(oldList, newList, operatedesc);

        return StringUtils.EMPTY;
    }

    /**
     * 记录日志
     *
     * @param oldSalaryArchiveList
     * @param newSalaryArchiveList
     * @param operatedesc
     */
    private void recordLog(List<SalaryArchivePO> oldSalaryArchiveList, List<SalaryArchivePO> newSalaryArchiveList, String operatedesc) {
        if (CollectionUtils.isEmpty(oldSalaryArchiveList) || CollectionUtils.isEmpty(oldSalaryArchiveList)) {
            return;
        }
        List<Long> updateEmpIds = newSalaryArchiveList.stream().map(SalaryArchivePO::getEmployeeId).distinct().collect(Collectors.toList());
        List<DataCollectionEmployee> employeeList = getSalaryEmployeeService(user).listByIds(updateEmpIds);
        Map<Long, String> empMap = SalaryEntityUtil.convert2Map(employeeList, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getUsername);


        // 获取所有个税扣缴义务人
        Collection<TaxAgentPO> taxAgents = getTaxAgentService(user).listAll();
        Map<Long, String> taxAgentMap = SalaryEntityUtil.convert2Map(taxAgents, TaxAgentPO::getId, TaxAgentPO::getName);
        String bar = "-";
        oldSalaryArchiveList.forEach(e -> {
            LoggerContext loggerContext = new LoggerContext();
            loggerContext.setUser(user);
            loggerContext.setTargetId(String.valueOf(e.getId()));
            loggerContext.setTargetName( Optional.ofNullable(taxAgentMap.get(e.getTaxAgentId())).orElse(StringUtils.EMPTY) + bar + Optional.ofNullable(empMap.get(e.getEmployeeId())).orElse(StringUtils.EMPTY) );
            loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
            loggerContext.setOperateTypeName(operatedesc);
            loggerContext.setOperatedesc(operatedesc);
            loggerContext.setOldValues(e);
            Optional<SalaryArchivePO> optionalNew = newSalaryArchiveList.stream().filter(n -> n.getId().equals(e.getId())).findFirst();
            loggerContext.setNewValues(optionalNew.isPresent() ? optionalNew.get() : null);
            SalaryElogConfig.salaryArchiveLoggerTemplate.write(loggerContext);
        });
    }


    @Override
    public List<SalaryArchiveDimissionPO> dimissionSets() {
        return salaryArchiveDimissionMapper.dimissionSets();
    }

    @Override
    public String saveDimissionSet(SalaryArchiveDimissionSaveParam saveParam) {
        Date now = new Date();
        List<SalaryArchiveDimissionPO> dimissionSets = dimissionSets();
        if (CollectionUtils.isNotEmpty(dimissionSets)) {
            SalaryArchiveDimissionPO po = dimissionSets.get(0);
            po.setDimissionTimeInterval(saveParam.getDimissionTimeInterval().getValue());
            po.setUpdateTime(now);
            salaryArchiveDimissionMapper.updateById(po);
        } else {
            salaryArchiveDimissionMapper.insert(SalaryArchiveDimissionPO.builder().dimissionTimeInterval(saveParam.getDimissionTimeInterval().getValue()).createTime(now).updateTime(now).creator((long) user.getUID()).tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY).build());
        }
        return StringUtils.EMPTY;
    }

    @Override
    public List<SalaryArchiveDataDTO> getSalaryArchiveData(LocalDateRange localDateRange, Collection<Long> employeeIds, Long taxAgentId) {
        return getSalaryArchiveData(localDateRange, employeeIds, taxAgentId, Boolean.FALSE);
    }

    @Override
    public List<SalaryArchiveDataDTO> getSalaryArchiveTaxAgentData(LocalDateRange localDateRange, Collection<Long> employeeIds, Long taxAgentId) {
        return getSalaryArchiveData(localDateRange, employeeIds, taxAgentId, Boolean.TRUE);
    }

    /**
     * 根据日期范围和人员获取薪资档案数据
     *
     * @param localDateRange
     * @param employeeIds
     * @param isOnlyTaxAgent
     * @return
     */
    private List<SalaryArchiveDataDTO> getSalaryArchiveData(LocalDateRange localDateRange, Collection<Long> employeeIds, Long taxAgentId, boolean isOnlyTaxAgent) {
        // 获取核算人员规则
        List<String> statusList = Collections.emptyList();
        SalarySysConfPO employeeRule = getSalarySysConfService(user).getOneByCode(SalarySysConstant.SALARY_ACCT_EMPLOYEE_RULE);
        if (Objects.isNull(employeeRule) || StringUtils.equals(employeeRule.getConfValue(), SalaryAcctEmployeeRuleEnum.BYPAYENDTIME.getValue())) {
            // 默认包含停薪列表
            statusList = Arrays.asList(SalaryArchiveStatusEnum.FIXED.getValue(), SalaryArchiveStatusEnum.SUSPEND.getValue(),
                    SalaryArchiveStatusEnum.STOP_FROM_SUSPEND.getValue());
        } else {
            // 仅包含发薪、待定薪
            statusList = Arrays.asList(SalaryArchiveStatusEnum.FIXED.getValue(), SalaryArchiveStatusEnum.SUSPEND.getValue());
        }
        // 获取薪资档案数据
        List<SalaryArchivePO> salaryArchiveList = listSome(SalaryArchivePO.builder().runStatusList(statusList).employeeIds(employeeIds).taxAgentId(taxAgentId).build());

        List<Long> allEmployeeIds = salaryArchiveList.stream().map(SalaryArchivePO::getEmployeeId).distinct().collect(Collectors.toList());
        // 获取所有可被引用的薪资项目
        List<SalaryItemPO> salaryItems = salaryItemMapper.getCanAdjustSalaryItems();
        Collection<Long> salaryItemIds = salaryItems.stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        // 获取薪资项目调整数据,isOnlyTaxAgent为true时不需要薪资项目数据
        List<SalaryArchiveItemPO> salaryArchiveItemDataList = isOnlyTaxAgent || CollectionUtils.isEmpty(salaryItemIds) ? Lists.newArrayList() : salaryArchiveItemMapper.listByParam(SalaryArchiveItemQueryParam.builder().salaryItemIds(salaryItemIds).employeeIds(employeeIds).effectiveTime(localDateRange.getEndDate()).build());

        return SalaryArchiveBO.buildSalaryArchiveData(salaryArchiveList, salaryArchiveItemDataList, localDateRange, allEmployeeIds, isOnlyTaxAgent);
    }


    @Override
    public void stopSalary(SalaryArchiveStopParam stopSalaryParam) {
        ValidUtil.doValidator(stopSalaryParam);
        stopSalaryParam.setPayEndDate(SalaryDateUtil.stringToDate(stopSalaryParam.getPayEndDateStr()));

        SalaryArchivePO po = getSalaryArchiveMapper().getById(stopSalaryParam.getSalaryArchiveId());

        if (po == null) {
            throw new SalaryRunTimeException("未找到薪资档案");
        }
        Date payStartDate = po.getPayStartDate();
        Date payEndDate = stopSalaryParam.getPayEndDate();
        if (payEndDate.before(payStartDate)) {
            throw new SalaryRunTimeException("最后缴纳日期应大于起始缴纳日期");
        }

        po.setPayEndDate(payEndDate);
        po.setUpdateTime(new Date());
        getSalaryArchiveMapper().update(po);

    }


    @Override
    public Map<String, Object> preview(SalaryArchiveImportHandleParam param) {
        //1、参数校验
        vaildImportParam(param);

        Map<String, Object> map = new HashMap<>();

        InputStream fileInputStream = null;
        try {

            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(param.getImageId()));

            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);

            map.put("headers", headers);
            map.put("list", ExcelParseHelper.parse2List(sheet, 1));

            return map;

        } finally {
            IOUtils.closeQuietly(fileInputStream);
        }
    }

    private void vaildImportParam(SalaryArchiveImportHandleParam param) {
        String imageId = param.getImageId();
        if (StringUtils.isBlank(imageId)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100593, "文件id为空"));
        }
        if (param.getListType() == null) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109712, "列表类型必传"));
        } else {
            // 定薪列表导入有调薪导入和初始化导入
            if (param.getListType().equals(SalaryArchiveListTypeEnum.FIXED.getValue())) {
                Optional<SalaryArchiveImportTypeEnum> optional = Arrays.stream(SalaryArchiveImportTypeEnum.values())
                        .filter(e -> StringUtils.isNotEmpty(param.getImportType()) && e.getValue().equals(param.getImportType())).findFirst();
                if (!optional.isPresent()) {
                    throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100593, "导入类型不正确"));
                }
            }
        }
    }

    private List<SalaryArchiveTaxAgentPO> getEffectiveTaxAgentList() {
        Date truncate = DateUtils.truncate(new Date(), Calendar.DATE);
        return salaryArchiveTaxAgentMapper.getEffectiveTaxAgentList(SalaryArchiveTaxAgentQueryParam.builder().effectiveTime(truncate).build());
    }

    private List<SalaryArchiveTaxAgentPO> getIneffectiveTaxAgentList() {
        Date truncate = DateUtils.truncate(new Date(), Calendar.DATE);
        return salaryArchiveTaxAgentMapper.getIneffectiveTaxAgentList(SalaryArchiveTaxAgentQueryParam.builder().effectiveTime(truncate).build());
    }


    /**
     * 处理历史数据
     * 下回发版可删除
     */
    public void handleHistory(Long currentEmployeeId) {
        // 待定薪没设置过的默认为正常工资薪金所得
//        new LambdaUpdateChainWrapper<>(salaryArchiveMapper)
//                .eq(SalaryArchivePO::getDeleteType, 0)
//                .eq(SalaryArchivePO::getTenantKey, tenantKey)
//                .eq(SalaryArchivePO::getRunStatus, SalaryArchiveStatusEnum.PENDING.getValue())
//                .isNull(SalaryArchivePO::getIncomeCategory)
//                .set(SalaryArchivePO::getIncomeCategory, IncomeCategoryEnum.WAGES_AND_SALARIES.getValue())
//                .update();

        //历史档案默认为发薪员工
        List<SalaryArchivePO> historyData = getSalaryArchiveMapper().getStatusIsNullData();
        List<Long> ids = SalaryEntityUtil.properties(historyData, SalaryArchivePO::getId, Collectors.toList());
        List<List<Long>> partIds = Lists.partition(ids, 999);
        for (List<Long> part : partIds) {
            getSalaryArchiveMapper().updateStatus(SalaryArchivePO.builder().ids(part).runStatus(SalaryArchiveStatusEnum.FIXED.getValue()).build());
        }

        //处理个税扣缴义务人为空
        List<SalaryArchivePO> salaryArchives = getSalaryArchiveMapper().getHistoryData();
        if (CollectionUtils.isEmpty(salaryArchives)) {
            return;
        }
        Date today = new Date();
        List<SalaryArchiveTaxAgentPO> salaryArchiveTaxAgents = getEffectiveTaxAgentList();

        List<SalaryArchiveItemPO> salaryArchiveItems = salaryArchiveItemMapper.getEffectiveSalaryItems(SalaryArchiveItemQueryParam.builder().effectiveTime(today).build());

        List<Long> salaryArchiveDelIds = salaryArchives.stream().map(SalaryArchivePO::getId).collect(Collectors.toList());
        List<Long> salaryArchiveTaxAgentDelIds = salaryArchiveTaxAgents.stream().map(SalaryArchiveTaxAgentPO::getId).collect(Collectors.toList());
        List<Long> salaryArchiveItemDelIds = salaryArchiveItems.stream().map(SalaryArchiveItemPO::getId).collect(Collectors.toList());

        List<SalaryArchivePO> salaryArchiveAddList = Lists.newArrayList();
        List<SalaryArchiveItemPO> salaryArchiveItemAddList = Lists.newArrayList();


        Date endDate = today;
        for (SalaryArchivePO sa : salaryArchives) {
            List<SalaryArchiveTaxAgentPO> saTaxAgents = salaryArchiveTaxAgents.stream().filter(t -> t.getSalaryArchiveId().equals(sa.getId())).collect(Collectors.toList());
            // 去重获取最新生效的个税口角义务人列表
            saTaxAgents = saTaxAgents.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getSalaryArchiveId() + "-" + f.getTaxAgentId()))), ArrayList::new));

            List<SalaryArchiveItemPO> saItemList = salaryArchiveItems.stream().filter(i -> i.getSalaryArchiveId().equals(sa.getId())).collect(Collectors.toList());

            for (SalaryArchiveTaxAgentPO st : saTaxAgents) {
                Date finalEndDate = endDate;
                List<SalaryArchiveItemPO> saItems = saItemList.stream().filter(si -> !si.getEffectiveTime().after(finalEndDate)).collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(f -> f.getSalaryArchiveId() + "-" + f.getSalaryItemId()))), ArrayList::new));

                SalaryArchivePO newSA = SalaryArchivePO.builder().id(IdGenerator.generate()).employeeId(sa.getEmployeeId()).taxAgentId(st.getTaxAgentId()).payStartDate(st.getEffectiveTime())
//                        .runStatus(SalaryArchiveStatusEnum.FIXED.getValue())
//                        .modifier(0L)
                        .createTime(today).updateTime(today).creator(currentEmployeeId).deleteType(NumberUtils.INTEGER_ZERO).tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY).build();
                salaryArchiveAddList.add(newSA);
                saItems.forEach(sf -> {
                    salaryArchiveItemAddList.add(SalaryArchiveItemPO.builder().salaryArchiveId(newSA.getId()).employeeId(newSA.getEmployeeId()).effectiveTime(sf.getEffectiveTime()).adjustReason(sf.getAdjustReason()).salaryItemId(sf.getSalaryItemId()).itemValue(sf.getItemValue()).description(sf.getDescription())
                            // 不用设置操作人
                            .operator(currentEmployeeId).operateTime(today).createTime(today).updateTime(today).creator(currentEmployeeId).deleteType(NumberUtils.INTEGER_ZERO).tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY).build());
                });

//                endDate = st.getEffectiveTime();
            }
        }

        // 逻辑删除历史数据
        List<List<Long>> partition = Lists.partition(salaryArchiveDelIds, 999);
        for (List<Long> part : partition) {
            salaryArchiveMapper.batchDeleteHistoryData(SalaryArchivePO.builder().ids(part).build());
        }
        List<List<Long>> partitionTA = Lists.partition(salaryArchiveTaxAgentDelIds, 999);
        for (List<Long> part : partitionTA) {
            salaryArchiveTaxAgentMapper.batchDeleteHistoryData(SalaryArchiveTaxAgentPO.builder().ids(part).build());
        }
        List<List<Long>> partitionItem = Lists.partition(salaryArchiveItemDelIds, 999);
        for (List<Long> part : partitionItem) {
            salaryArchiveItemMapper.batchDeleteHistoryData(SalaryArchiveItemPO.builder().ids(part).build());
        }
        // 新增迁移数据
        if (CollectionUtils.isNotEmpty(salaryArchiveAddList)) {
            this.salaryArchiveMapper.batchInsert(salaryArchiveAddList);
        }
        if (CollectionUtils.isNotEmpty(salaryArchiveItemAddList)) {
            this.salaryArchiveItemMapper.batchInsert(salaryArchiveItemAddList, user);
        }
        log.info("处理历史数据结束===============");
    }

    @Override
    public Map<String, Object> selectSalaryArchiveColumns(SalaryArchiveImportTypeEnum salaryArchiveImportTypeEnum) {
        HashMap<String, Object> map = Maps.newHashMap();
        //类型为档案初始化
        boolean isInit = salaryArchiveImportTypeEnum.getValue().equals(SalaryArchiveImportTypeEnum.INIT.getValue());
        //类型为调整个税扣缴义务人
        boolean isTaxAgentAdjust = salaryArchiveImportTypeEnum.getValue().equals(SalaryArchiveImportTypeEnum.TAXAGENTADJUST.getValue());
        //类型为调薪
        boolean isSalaryItemAdjust = salaryArchiveImportTypeEnum.getValue().equals(SalaryArchiveImportTypeEnum.SALARYITEMADJUST.getValue());

        //固定列
        map.put(SalaryI18nUtil.getI18nLabel(85429, "姓名"), "username");
        map.put(SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人"), "taxAgentName");
        map.put(SalaryI18nUtil.getI18nLabel(85904, "生效日期"), "taxAgentEffectiveTime");
        map.put(SalaryI18nUtil.getI18nLabel(86185, "部门"), "departmentName");
        map.put(SalaryI18nUtil.getI18nLabel(86186, "手机号"), "mobile");
        map.put(SalaryI18nUtil.getI18nLabel(91075, "员工状态"), "employeeStatus");

        List<SalaryItemPO> salaryItems = salaryItemMapper.getCanAdjustSalaryItems();

        if (isTaxAgentAdjust || isSalaryItemAdjust) {
            map.put(SalaryI18nUtil.getI18nLabel(85431, "调整原因"), "adjustReason");
        }
        //动态列
        // 获取所有可被引用的薪资项目
        if (isInit || isSalaryItemAdjust) {
            for (SalaryItemPO salaryItem : salaryItems) {
                map.put(salaryItem.getName(), salaryItem.getCode());
            }
        }

        return map;
    }

    @Override
    public Map<String, Long> queryTabTotal() {
        long currentEmployeeId = user.getUID();

        // tab页签数量
        Map<String, Long> result = new HashMap<>();

        Boolean needAuth = getTaxAgentService(user).isNeedAuth(currentEmployeeId);

        //获取管理的人员范围
        List<TaxAgentManageRangeEmployeeDTO> taxAgentEmployeeDTOS = getTaxAgentService(user).listTaxAgentAndEmployeeTree(currentEmployeeId);
        Map<Long, List<TaxAgentManageRangeEmployeeDTO.TaxAgentEmployee>> taxAgentEmployeesMap = SalaryEntityUtil.convert2Map(taxAgentEmployeeDTOS, TaxAgentManageRangeEmployeeDTO::getTaxAgentId, TaxAgentManageRangeEmployeeDTO::getEmployeeList);
        List<SalaryArchivePO> list = new ArrayList<>();
        if (needAuth) {
            // 获取作为管理员的所有个税扣缴义务人列表
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgentsAsAdmin(currentEmployeeId);
            Set<Long> taxAgentIds = SalaryEntityUtil.properties(taxAgentPOS, TaxAgentPO::getId);

            //获取所有薪资档案
            List<SalaryArchivePO> archiveListDTOS = getSalaryArchiveMapper().listAll();
            list = archiveListDTOS.stream().filter(dto -> taxAgentIds.contains(dto.getTaxAgentId())).collect(Collectors.toList());

            Boolean adminEnable = getTaxAgentService(user).isAdminEnable(currentEmployeeId);
            //不是管理员看不到数据，返回空
            if (!adminEnable) {
                list = new ArrayList<>();
            }

        } else {
            list = getSalaryArchiveMapper().listAll();
        }


        long pendingTotal = 0L;
        long fixedTotal = 0L;
        long suspendTotal = 0L;
        long stopTotal = 0L;
        long extTotal = 0L;

        for (SalaryArchivePO sa : list) {
            Integer employeeType = sa.getEmployeeType();
            if (employeeType == null || employeeType == 0) {
                if (sa.getRunStatus().equals(SalaryArchiveStatusEnum.PENDING.getValue())) {
                    pendingTotal += 1;
                } else if (sa.getRunStatus().equals(SalaryArchiveStatusEnum.FIXED.getValue()) || sa.getRunStatus().equals(SalaryArchiveStatusEnum.SUSPEND.getValue())) {
                    fixedTotal += 1;
                    if (sa.getRunStatus().equals(SalaryArchiveStatusEnum.SUSPEND.getValue())) {
                        suspendTotal += 1;
                    }
                } else if (sa.getRunStatus().equals(SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue()) || sa.getRunStatus().equals(SalaryArchiveStatusEnum.STOP_FROM_SUSPEND.getValue())) {
                    stopTotal += 1;
                }
            } else {
                extTotal += 1;
            }
        }

        result.put(SalaryArchiveListTypeEnum.PENDING.getValue(), pendingTotal);
        result.put(SalaryArchiveListTypeEnum.FIXED.getValue(), fixedTotal);
        result.put(SalaryArchiveListTypeEnum.SUSPEND.getValue(), suspendTotal);
        result.put(SalaryArchiveListTypeEnum.STOP.getValue(), stopTotal);
        result.put(SalaryArchiveListTypeEnum.EXT.getValue(), extTotal);
        return result;
    }

    @Override
    public String deletePendingTodo(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        List<SalaryArchivePO> oldList = listSome(SalaryArchivePO.builder()
                .ids(ids)
                .runStatus(SalaryArchiveStatusEnum.PENDING.getValue())
                .build());


        if (CollectionUtils.isEmpty(oldList)) {
            return StringUtils.EMPTY;
        }
        // 从待定薪到停薪
        getSalaryArchiveMapper().deletePendingTodo(ids);
        // 记录日志
        List<SalaryArchivePO> newList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(ids).build());
        String operatedesc = SalaryI18nUtil.getI18nLabel(0, "删除待办");
        recordLog(oldList, newList, operatedesc);

        return StringUtils.EMPTY;
    }


    @Override
    public Map<String, Object> gotoFixed(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(145969, "没有可以操作的记录"));
        }

        List<SalaryArchivePO> salaryArchiveList = listSome(SalaryArchivePO.builder().ids(ids).runStatus(SalaryArchiveStatusEnum.PENDING.getValue()).build());

        if (CollectionUtils.isEmpty(salaryArchiveList)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(145969, "档案不存在！"));
        }

        List<SalaryArchivePO> unableList = salaryArchiveList.stream().filter(f -> f.getPayStartDate() == null).collect(Collectors.toList());

        int total = ids.size();
        int errorCount = unableList.size();
        // 单个设为定薪的失败提示
        if (total == 1 && errorCount > 0) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109197, "请先维护起始发薪日期"));
        }

        // 从待定薪到定薪
        List<List<Long>> partition = Lists.partition((List<Long>) ids, 1000);
        partition.forEach(getSalaryArchiveMapper()::gotoFixed);

        // 记录日志
        List<SalaryArchivePO> newList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(ids).build());
        String operateDesc = SalaryI18nUtil.getI18nLabel(0, "设为发薪员工");
        recordLog(salaryArchiveList, newList, operateDesc);

        // 获取所有可被引用的薪资项目
        List<Long> salaryItemIds = getSalaryArchiveItemService(user).getCanAdjustSalaryItems().stream().map(SalaryItemPO::getId).collect(Collectors.toList());
        List<SalaryArchiveItemPO> currentEffectiveItemList = getSalaryArchiveItemService(user).getCurrentEffectiveItemListIngoreValue(ids, salaryItemIds)
                .stream()
                .peek(e -> {
                    Optional<SalaryArchivePO> salaryArchive = salaryArchiveList.stream().filter(sa -> sa.getId().equals(e.getSalaryArchiveId())).findFirst();
                    if (salaryArchive.isPresent()) {
                        e.setAdjustReason(SalaryArchiveItemAdjustReasonEnum.INIT.getValue());
                        e.setEffectiveTime(salaryArchive.get().getPayStartDate());
                    }
                }).collect(Collectors.toList());
        // 更新薪资项目的生效日期
        List<List<SalaryArchiveItemPO>> partitions = Lists.partition(currentEffectiveItemList, 100);
        partitions.forEach(list -> getSalaryArchiveItemMapper().batchUpdate(list));

        Map<String, Object> resultMap = new HashMap<>(2);
        String resultMsg = SalaryI18nUtil.getI18nLabel(94620, "操作成功");
        String resultType = "success";
        // 批量设为定薪提示
        if (total > 1) {
            resultMsg = SalaryI18nUtil.getI18nLabel(134807, "成功条数") + ": " + (total - errorCount) + "; "
                    + SalaryI18nUtil.getI18nLabel(134808, "失败条数") + ": " + (errorCount)
                    + (errorCount > 0 ? ", " + SalaryI18nUtil.getI18nLabel(109197, "请先维护起始发薪日期") : "");
            resultType = errorCount > 0 ? "info" : resultType;
        }
        resultMap.put("type", resultType);
        resultMap.put("msg", resultMsg);
        return resultMap;
    }

    @Override
    public Map<String, Object> allGotoFixed(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.PENDING.getValue()));
        List<Long> salaryArchiveIds = this.list(queryParam)
                .stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList());
        return this.gotoFixed(salaryArchiveIds);
    }


    @Override
    public Map<String, Object> gotoStop(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(145969, "没有可以操作的记录"));
        }
        List<SalaryArchivePO> oldList = listSome(SalaryArchivePO.builder()
                .ids(ids)
                .runStatus(SalaryArchiveStatusEnum.SUSPEND.getValue())
                .build());

        if (CollectionUtils.isEmpty(oldList)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(145969, "档案不存在！"));
        }

        List<SalaryArchivePO> unableList = oldList.stream().filter(f -> f.getPayEndDate() == null).collect(Collectors.toList());
        int total = ids.size();
        int errorCount = unableList.size();
        // 单个设为定薪的失败提示
        if (total == 1 && errorCount > 0) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(109196, "请先维护最后发薪日期"));
        }

        // 从待停薪到停薪
        getSalaryArchiveMapper().gotoStop(ids);

        // 记录日志
        List<SalaryArchivePO> newList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(ids).build());
        String operatedesc = SalaryI18nUtil.getI18nLabel(0, "停薪");
        recordLog(oldList, newList, operatedesc);

        Map<String, Object> resultMap = new HashMap<>(2);
        String resultMsg = SalaryI18nUtil.getI18nLabel(94620, "操作成功");
        String resultType = "success";
        // 批量设为定薪提示
        if (total > 1) {
            resultMsg = SalaryI18nUtil.getI18nLabel(134807, "成功条数") + ": " + (total - errorCount) + "; "
                    + SalaryI18nUtil.getI18nLabel(134808, "失败条数") + ": " + (errorCount)
                    + (errorCount > 0 ? ", " + SalaryI18nUtil.getI18nLabel(109196, "请先维护最后发薪日期") : "");
            resultType = errorCount > 0 ? "info" : resultType;
        }
        resultMap.put("type", resultType);
        resultMap.put("msg", resultMsg);
        return resultMap;
    }

    @Override
    public Map<String, Object> allGotoStop(SalaryArchiveQueryParam queryParam) {
        queryParam.setRunStatusList(Arrays.asList(SalaryArchiveStatusEnum.SUSPEND.getValue()));
        List<Long> salaryArchiveIds = this.list(queryParam)
                .stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList());
        return this.gotoStop(salaryArchiveIds);
    }

    @Override
    public String deleteSuspendTodo(Collection<Long> ids) {
        if (org.springframework.util.CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

//        List<SalaryArchivePO> oldList = listSome(SalaryArchivePO.builder()
//                .ids(ids)
//                .runStatus(SalaryArchiveStatusEnum.SUSPEND.getValue())
//                .build());
//        List<SalaryArchivePO> unableList = oldList.stream().filter(f -> Objects.nonNull(f.getPayEndDate()) && !f.getPayEndDate().after(new Date())).collect(Collectors.toList());
//        if (CollectionUtils.isNotEmpty(unableList)) {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(115789, "最后发薪日必须晚于今天"));
//        }
//
//        // 从待停薪到定薪
//        getSalaryArchiveMapper().deleteSuspendTodo(ids);
//        return StringUtils.EMPTY;

        // 获取所有个税扣缴义务人
//        Collection<TaxAgentManageRangeEmployeeDTO> taxAgentList = getTaxAgentService(user).listTaxAgentAndEmployeeTree(Long.valueOf(user.getUID()));
        Collection<TaxAgentManageRangeEmployeeDTO> taxAgentList = getTaxAgentService(user).listTaxAgentAndEmployeeTree();
        // 获取删除待停薪信息
        List<SalaryArchiveListDTO> list = getSalaryArchiveMapper().list(SalaryArchiveQueryParam.builder().ids(ids).build());
        if (list.size() != ids.size()) {
            throw new SalaryRunTimeException("薪资档案不存在，删除失败！");
        }
        Set<String> employeeStatus = list.stream().map(SalaryArchiveListDTO::getEmployeeStatus).collect(Collectors.toSet());
        if (employeeStatus.contains("5")) {
            throw new SalaryRunTimeException("离职人员无法删除待办");
        }
        Map<Long, TaxAgentManageRangeEmployeeDTO> taxAgentMap = SalaryEntityUtil.convert2Map(taxAgentList, TaxAgentManageRangeEmployeeDTO::getTaxAgentId);
        // 判断删除待停薪代办的人是否在个税扣缴义务人的人员范围中
        for (SalaryArchiveListDTO dto : list) {
            TaxAgentManageRangeEmployeeDTO taxAgentManageRangeEmployeeDTO = taxAgentMap.get(dto.getTaxAgentId());
            if (Objects.nonNull(taxAgentManageRangeEmployeeDTO)) {
                boolean canDelete = taxAgentManageRangeEmployeeDTO.getEmployeeList().stream()
                        .map(TaxAgentManageRangeEmployeeDTO.TaxAgentEmployee::getEmployeeId)
                        .anyMatch(id -> Objects.equals(id, dto.getEmployeeId()));
                if (!canDelete) {
                    throw new SalaryRunTimeException("个税扣缴义务人不存在或不在权限范围内，删除失败！");
                }
            } else {
                throw new SalaryRunTimeException("个税扣缴义务人不存在或不在权限范围内，删除失败！");
            }
        }
        // 删除最后发薪日期，设置状态为发薪
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> salaryArchiveIds = list.stream().map(SalaryArchiveListDTO::getId).collect(Collectors.toList());
            getSalaryArchiveMapper().deleteSuspendTodo(salaryArchiveIds);
            // 记录日志
            List<SalaryArchivePO> oldList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(salaryArchiveIds).build());
            List<SalaryArchivePO> newList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(ids).build());
            String operatedesc = SalaryI18nUtil.getI18nLabel(0, "删除待办");
            recordLog(oldList, newList, operatedesc);
        }
        return StringUtils.EMPTY;
    }

    @Override
    public String cancelStop(Collection<Long> ids) {
        if (org.springframework.util.CollectionUtils.isEmpty(ids)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        List<SalaryArchivePO> oldList = listSome(
                SalaryArchivePO.builder()
                        .ids(ids)
                        .runStatusList(Arrays.asList(SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue(), SalaryArchiveStatusEnum.STOP_FROM_SUSPEND.getValue()))
                        .build());


        if (CollectionUtils.isEmpty(oldList)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(145969, "档案不存在！"));
        }


        List<TaxAgentEmployeeDTO> taxAgentManageRangeEmployees = getTaxAgentService(user).listAllTaxAgentAndEmployee();
        List<SalaryArchivePO> oldPendingList = oldList.stream().filter(f -> f.getRunStatus().equals(SalaryArchiveStatusEnum.STOP_FROM_PENDING.getValue())).collect(Collectors.toList());
        boolean isNotExist = oldPendingList.stream().anyMatch(te -> taxAgentManageRangeEmployees.stream().noneMatch(p -> p.getEmployeeId() != null && p.getEmployeeId().equals(te.getEmployeeId()) && p.getTaxAgentId().equals(te.getTaxAgentId())));
        if (isNotExist) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(116196, "不在当前个税扣缴义人的人员范围中，不可取消停薪"));
        }
        // 从停薪到待定薪
        getSalaryArchiveMapper().gotoPendingFromStop(ids);
        // 从停薪到定薪
        getSalaryArchiveMapper().gotoFixedFromStop(ids);

        // 记录日志
        List<SalaryArchivePO> newList = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().ids(ids).build());
        String operatedesc = SalaryI18nUtil.getI18nLabel(0, "取消停薪");
        recordLog(oldList, newList, operatedesc);

        return StringUtils.EMPTY;
    }

    @Override
    public Map<String, Object> handleRepeatData() {
        Map<String, Object> result = new HashMap<>();

        //获取所有薪资档案
        List<SalaryArchivePO> list = getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().runStatus(SalaryArchiveStatusEnum.PENDING.getValue()).build());
        AtomicInteger num = new AtomicInteger();
        if (CollectionUtils.isNotEmpty(list)) {
            Map<String, List<SalaryArchivePO>> maps = SalaryEntityUtil.group2Map(list, k -> k.getTaxAgentId() + "-" + k.getEmployeeId());
            maps.forEach((key, pos) -> {
                if (pos.size() > 1) {
                    for (int i = 1; i < pos.size(); i++) {
                        SalaryArchivePO salaryArchivePO = pos.get(i);
                        getSalaryArchiveMapper().delete(salaryArchivePO);
                        num.getAndIncrement();
                    }
                }
            });
        }
        result.put("共处理", num.get());
        return result;
    }

    @Override
    public List<SalaryArchivePO> listPayEndDateIsNull(List<Long> employeeIds) {
        if (CollectionUtils.isEmpty(employeeIds)) {
            return Collections.emptyList();
        }
        return getSalaryArchiveMapper().listPayEndDateIsNull(employeeIds);
    }

    @Override
    public List<SalaryArchivePO> listByRunStatus(List<String> list) {
        return getSalaryArchiveMapper().listSome(SalaryArchivePO.builder().runStatusList(list).build());
    }

    /**
     * 同步所有档案起始发薪日期变为入职日期
     *
     * @return
     */
    @Override
    public String syncPayStartDate() {
        List<DataCollectionEmployee> employeeList = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);
        Map<Long, String> empPayStartDateMap = SalaryEntityUtil.convert2Map(employeeList, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getCompanystartdate);

        List<SalaryArchivePO> list = getSalaryArchiveMapper().listAll();
        List<SalaryArchivePO> archives = list.stream()
                .peek(archive -> {
                    String payStartDate = empPayStartDateMap.getOrDefault(archive.getEmployeeId(), "");
                    if (SalaryDateUtil.checkDay(payStartDate)) {
                        archive.setPayStartDate(SalaryDateUtil.dateStrToLocalDate(payStartDate));
                    }
                })
                .collect(Collectors.toList());
        salaryArchiveMapper.batchUpdate(archives);
        return "执行完毕";
    }

    @Override
    public List<SalaryArchivePO> listPayStartDateIsNull(String runStatus) {
        if (StringUtils.isBlank(runStatus)) {
            return Collections.emptyList();
        }
        return getSalaryArchiveMapper().listPayStartDateIsNull(runStatus);
    }
}
