package com.engine.salary.service.impl;

import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.common.LocalDateRange;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.entity.salaryBill.po.SalarySendPO;
import com.engine.salary.entity.salaryacct.bo.SalaryAcctRecordBO;
import com.engine.salary.entity.salaryacct.param.SalaryAcctRecordQueryParam;
import com.engine.salary.entity.salaryacct.param.SalaryAcctRecordSaveParam;
import com.engine.salary.entity.salaryacct.po.SalaryAcctEmployeePO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctRecordPO;
import com.engine.salary.entity.salaryacct.po.SalaryAcctResultPO;
import com.engine.salary.entity.salarysob.dto.SalarySobCycleDTO;
import com.engine.salary.entity.salarysob.po.SalarySobPO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.salaryaccounting.SalaryAcctRecordStatusEnum;
import com.engine.salary.enums.salarysob.IncomeCategoryEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.salaryacct.SalaryAcctRecordMapper;
import com.engine.salary.mapper.salarybill.SalarySendMapper;
import com.engine.salary.report.service.SalaryStatisticsReportService;
import com.engine.salary.report.service.impl.SalaryStatisticsReportServiceImpl;
import com.engine.salary.service.*;
import com.engine.salary.sys.enums.TaxDeclarationFunctionEnum;
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.MapperProxyFactory;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.hrm.User;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 薪资核算
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
public class SalaryAcctRecordServiceImpl extends Service implements SalaryAcctRecordService {

    private SalaryAcctRecordMapper getSalaryAcctRecordMapper() {
        return MapperProxyFactory.getProxy(SalaryAcctRecordMapper.class);
    }

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


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


    private SalaryAcctResultService getSalaryAcctResultService(User user) {
        return ServiceUtil.getService(SalaryAcctResultServiceImpl.class, user);
    }


    private SalarySendService getSalarySendService(User user) {
        return ServiceUtil.getService(SalarySendServiceImpl.class, user);
    }

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

    private SalarySobItemService getSalarySobItemService(User user) {
        return ServiceUtil.getService(SalarySobItemServiceImpl.class, user);
    }

    //    private SalaryCheckResultService salaryCheckResultService;
//
//    private SalaryCheckResultDetailService salaryCheckResultDetailService;
//
    private SalaryComparisonResultService getSalaryComparisonResultService(User user) {
        return ServiceUtil.getService(SalaryComparisonResultServiceImpl.class, user);
    }

    private TaxDeclarationService getTaxDeclarationService(User user) {
        return ServiceUtil.getService(TaxDeclarationServiceImpl.class, user);
    }

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


    private SalaryAcctReportService getSalaryAcctReportService(User user) {
        return ServiceUtil.getService(SalaryAcctReportServiceImpl.class, user);
    }

    private SalaryStatisticsReportService getSalaryStatisticsReportService(User user) {
        return ServiceUtil.getService(SalaryStatisticsReportServiceImpl.class, user);
    }

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


    @Override
    public SalaryAcctRecordPO getById(Long id) {
        return getSalaryAcctRecordMapper().getById(id);
    }

    @Override
    public List<SalaryAcctRecordPO> listAll() {
        return getSalaryAcctRecordMapper().listAll();
    }

    @Override
    public List<SalaryAcctRecordPO> listByIds(Collection<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().ids(ids).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listBySalarySobIdsAndSalaryMonth(Collection<Long> salarySobIds, LocalDateRange salaryMonthDateRange) {
        if (CollectionUtils.isEmpty(salarySobIds)) {
            return Collections.emptyList();
        }
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().salarySobIds(salarySobIds).salaryMonths(salaryMonthDateRange).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listBySalarySobIdsAndTaxCycle(Collection<Long> salarySobIds, LocalDateRange taxCycleDateRange) {
        if (CollectionUtils.isEmpty(salarySobIds)) {
            return Collections.emptyList();
        }
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().salarySobIds(salarySobIds).taxCycleDateRange(taxCycleDateRange).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listBySalaryMonth(LocalDateRange salaryMonthDateRange) {
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().salaryMonths(salaryMonthDateRange).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listByTaxCycle(LocalDateRange taxCycleDateRange, Collection<Long> salarySobIds) {
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().taxCycleDateRange(taxCycleDateRange).salarySobIds(salarySobIds).build());
    }

    private SalarySendMapper getSalarySendMapper() {
        return SqlProxyHandle.getProxy(SalarySendMapper.class);
    }

    @Override
    public PageInfo<SalaryAcctRecordPO> listPageByParam(SalaryAcctRecordQueryParam queryParam) {
        long currentEmployeeId = user.getUID();
        // 参数
        SalaryAcctRecordPO po = SalaryAcctRecordPO.builder().build();
        PageInfo<SalaryAcctRecordPO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize());
        if (StringUtils.isNotEmpty(queryParam.getName())) {
            // 根据查询条件中的薪资账套名称查询薪资账套
            List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByNameLike(queryParam.getName());
            if (CollectionUtils.isEmpty(salarySobPOS)) {
                return page;
            }
            // 过滤薪资账套
            Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
            po.setSalarySobIds(salarySobIds);
        }
        LocalDateRange localDateRange = new LocalDateRange();
        if (Objects.nonNull(queryParam.getStartMonth())) {
            localDateRange.setFromDate(SalaryDateUtil.localDateToDate(queryParam.getStartMonth().atDay(1)));
        }
        if (Objects.nonNull(queryParam.getEndMonth())) {
            localDateRange.setEndDate(SalaryDateUtil.localDateToDate(queryParam.getEndMonth().atEndOfMonth()));
        }
        po.setSalaryMonths(localDateRange);


        // 判断是否开启了分权
        Boolean needAuth = getTaxAgentService(user).isNeedAuth(currentEmployeeId);
        if (needAuth) {
            List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByAdmin();
            List<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId, Collectors.toList());

            if (CollectionUtils.isEmpty(salarySobIds)) {
                return new PageInfo<>();
            }
            Collection<Long> sobIds = po.getSalarySobIds();
            if (CollectionUtils.isNotEmpty(sobIds)) {
                salarySobIds = (List<Long>) SalaryEntityUtil.intersectionForList(salarySobIds, sobIds);
            }
            po.setSalarySobIds(salarySobIds);
        }

        // 查询薪资核算记录
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = getSalaryAcctRecordMapper().listSome(po);
        return SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                salaryAcctRecordPOS, SalaryAcctRecordPO.class);
    }

    @Override
    public List<SalaryAcctRecordPO> listById4LastSalaryMonth(Long id) {
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getById(id);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }

        //上个月日期
        Date salaryMonth = salaryAcctRecordPO.getSalaryMonth();
        Calendar prevMonth = Calendar.getInstance();
        prevMonth.setTime(salaryMonth);
        prevMonth.set(Calendar.MONTH, prevMonth.get(Calendar.MONTH) - 1);

        // 查询上个月的核算记录
        LocalDateRange salaryMonthDateRange = SalaryDateUtil.localDate2Range(prevMonth.getTime());
        return listBySalarySobIdsAndSalaryMonth(Collections.singleton(salaryAcctRecordPO.getSalarySobId()),
                salaryMonthDateRange);
    }

    @Override
    public List<SalaryAcctRecordPO> listBySalarySobIds(Collection<Long> salarySobIds) {
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().salarySobIds(salarySobIds).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listById4OtherConsolidatedTax(Long id) {
        SalaryAcctRecordPO salaryAcctRecordPO = getById(id);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 查询所有薪资类型为工资薪金的账套
        List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByIncomeCategory(IncomeCategoryEnum.WAGES_AND_SALARIES);
        // 如果薪资账套的薪资类型不是工资薪金的，代表不存在合并计税
        boolean isWageSalarySob = salarySobPOS.stream().anyMatch(salarySobPO -> Objects.equals(salarySobPO.getId(), salaryAcctRecordPO.getSalarySobId()));
        if (!isWageSalarySob) {
            return Collections.emptyList();
        }
        // 查询相同税款所属期内的薪资类型为工资薪金的账套的所有核算记录
        Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
        LocalDateRange taxCycleDateRange = SalaryDateUtil.localDate2Range(salaryAcctRecordPO.getTaxCycle());
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByTaxCycle(taxCycleDateRange, salarySobIds);
        // 除开本次薪资核算记录之外的其他薪资核算记录
        return salaryAcctRecordPOS.stream().filter(po -> !Objects.equals(po.getId(), salaryAcctRecordPO.getId())).collect(Collectors.toList());
    }

    @Override
    public SalarySobCycleDTO getSalarySobCycleById(Long id) {
        // 查询薪资核算
        SalaryAcctRecordPO salaryAcctRecordPO = getById(id);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 查询薪资核算所用薪资账套的薪资周期、考勤周期……
        return getSalarySobService(user).getSalarySobCycle(salaryAcctRecordPO.getSalarySobId(), SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getSalaryMonth()));

    }

    @Override
    public Long save(SalaryAcctRecordSaveParam saveParam) {
        ValidUtil.doValidator(saveParam);
        //检查
        checkBeforeSave(saveParam);


        // 查询税款所属期
        SalarySobCycleDTO salarySobCycleDTO = getSalarySobService(user).getSalarySobCycle(saveParam.getSalarySobId(), saveParam.getSalaryMonth());
        // 薪资所属月所在年的日期范围（第一天～最后一天）
        LocalDateRange yearRange = SalaryDateUtil.localDate2YearRange(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1)));
        if (Objects.isNull(yearRange)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        // 查询税款所属期所在年的所有薪资核算记录
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByTaxCycle(yearRange, Collections.singleton(saveParam.getSalarySobId()));

        // 计算当前所选的薪资账套是当前薪资所属月的核算次数
        long acctTimes = salaryAcctRecordPOS.stream()
                .filter(salaryAcctRecordPO -> Objects.equals(salaryAcctRecordPO.getSalarySobId(), saveParam.getSalarySobId())
                        && salaryAcctRecordPO.getTaxCycle().equals(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))))
                .count();

        // 转换成po
        SalaryAcctRecordPO salaryAcctRecordPO = SalaryAcctRecordBO.convert2PO(saveParam, salarySobCycleDTO, (int) acctTimes, (long) user.getUID());
        // 保存薪资核算记录
        getSalaryAcctRecordMapper().insertIgnoreNull(salaryAcctRecordPO);
        // 初始化薪资核算人员
        getSalaryAcctEmployeeService(user).initBySalaryAcctRecord(salaryAcctRecordPO);
        // 记录日志
        String targetName = getLogTargetNameById(salaryAcctRecordPO.getId());
        LoggerContext<SalaryAcctRecordPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + salaryAcctRecordPO.getId());
        loggerContext.setTargetName(targetName);
        loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新建薪资核算"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新建薪资核算") + ": " + targetName);
        loggerContext.setNewValues(salaryAcctRecordPO);
        SalaryElogConfig.salaryAcctRecordLoggerTemplate.write(loggerContext);
        // 返回薪资核算记录id
        return salaryAcctRecordPO.getId();
    }


    /**
     * 保存之前检查一下是否可以新建核算
     *
     * @param saveParam
     */
    private void checkBeforeSave(SalaryAcctRecordSaveParam saveParam) {

        // 查询税款所属期
        SalarySobCycleDTO salarySobCycleDTO = getSalarySobService(user).getSalarySobCycle(saveParam.getSalarySobId(), saveParam.getSalaryMonth());
        // 薪资所属月所在年的日期范围（第一天～最后一天）
        LocalDateRange taxCycleYearRange = SalaryDateUtil.localDate2YearRange(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1)));
        if (Objects.isNull(taxCycleYearRange)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "参数错误"));
        }

        //获取账套所属个税扣缴义务人的核算记录
        SalarySobPO salarySobPO = getSalarySobService(user).getById(saveParam.getSalarySobId());
        Long taxAgentId = salarySobPO.getTaxAgentId();
        //查询扣缴义务人下的所有账套
        List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByTaxAgentId(taxAgentId);
        Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
        //获取账套下的所有核算结果
        List<SalaryAcctRecordPO> salaryAcctRecords = listByTaxCycle(taxCycleYearRange, salarySobIds);

        // 获取个税申报功能状态
        TaxDeclarationFunctionEnum taxDeclarationFunctionEnum = getSalarySysConfService(user).getTaxDeclaration();

//        if (taxDeclarationFunctionEnum.getValue().equals(TaxDeclarationFunctionEnum.CLOSURE.getValue())) {
//            // 关闭了个税申报功能
//            // 如果某个月（薪资所属期）还未归档，不可以新建之后月份的薪资核算
//            SalaryAcctRecordPO notArchivedSalaryAcctRecordPO = salaryAcctRecords.stream()
//                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue())
//                            && e.getSalaryMonth().before(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getSalaryMonth().atDay(1))))
//                    .findAny()
//                    .orElse(null);
//            if (Objects.nonNull(notArchivedSalaryAcctRecordPO)) {
//                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98754, "薪资所属期{0}的薪资核算结果还未归档，不能新建薪资所属期{1}的薪资核算")
//                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(notArchivedSalaryAcctRecordPO.getTaxCycle()).toString())
//                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
//            }
//            // 如果有某个月（薪资所属期）已经归档了，不可以新建之前月份的薪资核算
//            SalaryAcctRecordPO havaSalaryAcctRecordPO = salaryAcctRecords.stream()
//                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.ARCHIVED.getValue())
//                            && e.getTaxCycle().after(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getSalaryMonth().atDay(1))))
//                    .findAny()
//                    .orElse(null);
//            if (Objects.nonNull(havaSalaryAcctRecordPO)) {
//                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98755, "薪资所属期{0}的薪资核算结果已经归档，不能新建薪资所属期{1}的薪资核算")
//                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(havaSalaryAcctRecordPO.getSalaryMonth()).toString())
//                        .replace("{1}", salarySobCycleDTO.getSalaryMonth().toString()));
//            }
//
//        }
        if (taxDeclarationFunctionEnum.getValue().equals(TaxDeclarationFunctionEnum.OPEN.getValue())) {
            // 开启了个税申报功能
            // 如果某个月（税款所属期）已经归档了，不可以新建之前月份的薪资核算
            SalaryAcctRecordPO hasArchivedSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.ARCHIVED.getValue())
                            && e.getTaxCycle().after(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))))
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(hasArchivedSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98752, "税款所属期{0}的薪资核算结果已经归档，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(hasArchivedSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }
            // 如果某个月（税款所属期）还未申报，不可以新建之后月份的薪资核算
            SalaryAcctRecordPO notDeclaredSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> !Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.DECLARED.getValue())
                            && e.getTaxCycle().before(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))))
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(notDeclaredSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98751, "税款所属期{0}的薪资核算结果还未申报，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(notDeclaredSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }
            // 如果某个月（税款所属期）已经申报了，不可以新建本月以及之前月份的薪资核算
            SalaryAcctRecordPO hasDeclaredSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.DECLARED.getValue())
                            && e.getTaxCycle().compareTo(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))) >= 0)
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(hasDeclaredSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98753, "税款所属期{0}的薪资核算结果已经申报，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(hasDeclaredSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }
        }
        if (taxDeclarationFunctionEnum.getValue().equals(TaxDeclarationFunctionEnum.REBOOT.getValue())) {
            // 重启了个税申报功能（不去校验重启之前是否申报数据）
            // 如果某个月（薪资所属期）还未归档，不可以新建之后月份的薪资核算
            SalaryAcctRecordPO notArchivedSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue())
                            && e.getSalaryMonth().before(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getSalaryMonth().atDay(1))))
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(notArchivedSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98754, "薪资所属期{0}的薪资核算结果还未归档，不能新建薪资所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(notArchivedSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }
            // 如果某个月（税款所属期）已经归档了，不可以新建之前月份的薪资核算
            SalaryAcctRecordPO hasArchivedSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.ARCHIVED.getValue())
                            && e.getTaxCycle().after(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))))
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(hasArchivedSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98752, "税款所属期{0}的薪资核算结果已经归档，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(hasArchivedSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }
            // 如果某个月（税款所属期）还未申报，不可以新建之后月份的薪资核算
            //获取账套下从重启月至所在年的最后一天的所有核算结果
            Date taxDeclarationRebootDate = getSalarySysConfService(user).getTaxDeclarationRebootDate();
            if (taxDeclarationRebootDate == null) {
                throw new SalaryRunTimeException("个税申报功能异常");
            }

            LocalDateRange taxCycleRebootYearRange = LocalDateRange.builder()
                    .fromDate(taxDeclarationRebootDate)
                    .endDate(SalaryDateUtil.getLastDayOfYear(taxDeclarationRebootDate))
                    .build();
//            List<SalaryAcctRecordPO> salaryAcctRebootRecords = listByTaxCycle(taxCycleRebootYearRange,salarySobIds);
            List<SalaryAcctRecordPO> salaryAcctRebootRecords = listByCreateDate(taxCycleRebootYearRange, salarySobIds);
            SalaryAcctRecordPO notDeclaredSalaryAcctRecordPO = salaryAcctRebootRecords.stream()
                    .filter(e -> !Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.DECLARED.getValue())
                            && e.getTaxCycle().before(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))))
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(notDeclaredSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98751, "税款所属期{0}的薪资核算结果还未申报，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(notDeclaredSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }

            // 如果某个月（税款所属期）已经申报了，不可以新建本月以及之前月份的薪资核算
            SalaryAcctRecordPO hasDeclaredSalaryAcctRecordPO = salaryAcctRecords.stream()
                    .filter(e -> Objects.equals(e.getStatus(), SalaryAcctRecordStatusEnum.DECLARED.getValue())
                            && e.getTaxCycle().compareTo(SalaryDateUtil.localDateToDate(salarySobCycleDTO.getTaxCycle().atDay(1))) >= 0)
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(hasDeclaredSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98753, "税款所属期{0}的薪资核算结果已经申报，不能新建税款所属期{1}的薪资核算")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(hasDeclaredSalaryAcctRecordPO.getTaxCycle()).toString())
                        .replace("{1}", salarySobCycleDTO.getTaxCycle().toString()));
            }

        }

    }

    private List<SalaryAcctRecordPO> listByCreateDate(LocalDateRange taxCycleRebootYearRange, Set<Long> salarySobIds) {
        return getSalaryAcctRecordMapper().listByCreateDate(taxCycleRebootYearRange, salarySobIds);
    }


    @Override
    public void updateStatusByIds(Collection<Long> ids, SalaryAcctRecordStatusEnum status) {
        // 查询薪资核算记录
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByIds(ids);
        if (CollectionUtils.isEmpty(salaryAcctRecordPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 更新薪资核算记录的状态
        Date now = new Date();
        salaryAcctRecordPOS.forEach(salaryAcctRecordPO -> {
            salaryAcctRecordPO.setStatus(status.getValue());
            salaryAcctRecordPO.setUpdateTime(now);
            getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);
        });
    }

    @Override
    public void deleteByIds(Collection<Long> ids) {
        // 查询薪资核算记录
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByIds(ids);
        if (CollectionUtils.isEmpty(salaryAcctRecordPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        ids = SalaryEntityUtil.properties(salaryAcctRecordPOS, SalaryAcctRecordPO::getId);
        // 只有未归档的薪资核算记录才允许删除
        boolean hasArchived = salaryAcctRecordPOS.stream().anyMatch(salaryAcctRecordPO -> !Objects.equals(salaryAcctRecordPO.getStatus(), SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue()));
        if (hasArchived) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98748, "只有未归档的薪资核算记录才允许删除"));
        }
        // 查询账套（记录日志用）
        Set<Long> salarySobIds = SalaryEntityUtil.properties(salaryAcctRecordPOS, SalaryAcctRecordPO::getSalarySobId);
        List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByIds(salarySobIds);
        Map<Long, SalarySobPO> salarySobPOMap = SalaryEntityUtil.convert2Map(salarySobPOS, SalarySobPO::getId);
        // 删除薪资核算记录
        getSalaryAcctRecordMapper().deleteByIds(ids);
        //删除薪资核算人员
        getSalaryAcctEmployeeService(user).deleteBySalaryAcctRecordIds(ids);
        // 删除薪资核算结果
        getSalaryAcctResultService(user).deleteBySalaryAcctRecordIds(ids);
        //报表
        getSalaryAcctReportService(user).deleteBySalaryAcctRecordIds(ids);
        // 删除校验异常
//        salaryCheckResultService.deleteBySalaryAcctRecordIds(ids);
        // 删除校验异常明细
//        salaryCheckResultDetailService.deleteBySalaryAcctRecordIds(ids);
        // 删除线下导入结果
        getSalaryComparisonResultService(user).deleteBySalaryAcctRecordIds(ids);
        // 删除回算前的工资单
//        getSalarySendService(user).deleteBySalaryAcctRecordIds(ids);


        // 变更核算次数
        List<SalaryAcctRecordPO> toUpdateAcctTimesRecordPOS = listBySalarySobIds(salarySobIds);
        toUpdateAcctTimesRecordPOS = SalaryAcctRecordBO.updateAcctTimes(salaryAcctRecordPOS, toUpdateAcctTimesRecordPOS);
        for (SalaryAcctRecordPO salaryAcctRecordPO : toUpdateAcctTimesRecordPOS) {
            getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);
        }

        // 记录日志
        salaryAcctRecordPOS.forEach(salaryAcctRecordPO -> {
            SalarySobPO salarySobPO = salarySobPOMap.get(salaryAcctRecordPO.getSalarySobId());
            String targetName = salarySobPO.getName() + SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getSalaryMonth());
            LoggerContext<SalaryAcctRecordPO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId("" + salaryAcctRecordPO.getId());
            loggerContext.setTargetName(targetName);
            loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "删除薪资核算"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "删除薪资核算") + ":" + targetName);
            loggerContext.setNewValues(salaryAcctRecordPO);
            SalaryElogConfig.salaryAcctRecordLoggerTemplate.write(loggerContext);
        });
    }

    @Override
    public void file(Long salaryAcctRecordId) {
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getById(salaryAcctRecordId);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        //todo 如果存在未忽略的校验异常，不允许归档
//        List<SalaryCheckResultPO> salaryCheckResultPOS = salaryCheckResultService.listBySalaryAcctRecordIdAndIgnoreType(salaryAcctRecordId, NumberUtils.INTEGER_ZERO);
//        if (CollectionUtils.isNotEmpty(salaryCheckResultPOS)) {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98784, "核算结果尚未通过校验规则，请确认是否需要忽略校验异常后再归档"));
//        }
        List<SalaryAcctResultPO> salaryAcctResultPOS = getSalaryAcctResultService(user).listBySalaryAcctRecordIds(Collections.singleton(salaryAcctRecordId));
        if (CollectionUtils.isEmpty(salaryAcctResultPOS)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99691, "尚未核算，请先核算后再归档"));
        }
        // 更新薪资核算记录的状态
        salaryAcctRecordPO.setStatus(SalaryAcctRecordStatusEnum.ARCHIVED.getValue());
        salaryAcctRecordPO.setUpdateTime(new Date());
        getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);

        // 生成工资单
        getSalarySendService(user).generateSalaryBill(salaryAcctRecordId);

        //删除报表缓存
        getSalaryStatisticsReportService(user).removeReportCache();


        // 记录日志
        String targetName = getLogTargetNameById(salaryAcctRecordId);
        LoggerContext<SalaryAcctRecordPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + salaryAcctRecordPO.getId());
        loggerContext.setTargetName(targetName);
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "薪资核算归档"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "薪资核算归档") + ": " + targetName);
        loggerContext.setNewValues(salaryAcctRecordPO);
        SalaryElogConfig.salaryAcctRecordLoggerTemplate.write(loggerContext);
    }

    @Override
    public void reCalculate(Long salaryAcctRecordId) {
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getById(salaryAcctRecordId);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 重新核算
        reCalcOrBackCalc(salaryAcctRecordPO, true);


//        // 查询税款所在年的该个税扣缴义务人所有薪资核算记录
//        // 获取账套所属个税扣缴义务人的核算记录
//        SalarySobPO salarySobPO = getSalarySobService(user).getById(salaryAcctRecordPO.getSalarySobId());
//        Long taxAgentId = salarySobPO.getTaxAgentId();
//        //查询扣缴义务人下的所有账套
//        List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByTaxAgentId(taxAgentId);
//        Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
//        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByTaxCycle(yearRange,salarySobIds);
//        List<SalaryAcctRecordPO> selfSalaryAcctRecordPOS = filterByAuthority(salaryAcctRecordPOS);
//        // 如果已经存在之后月份的薪资核算记录了，就不允许重新核算本月了
//        SalaryAcctRecordPO afterSalaryAcctRecordPO = selfSalaryAcctRecordPOS.stream()
//                .filter(po -> po.getSalaryMonth().compareTo(salaryAcctRecordPO.getSalaryMonth()) > 0)
//                .findAny()
//                .orElse(null);
//        if (Objects.nonNull(afterSalaryAcctRecordPO)) {
//            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(105826, "已经存在{0}的薪资核算记录了，不能重新核算{1}的薪资了")
//                    .replace("{0}", SalaryDateUtil.localDate2YearMonth(afterSalaryAcctRecordPO.getSalaryMonth()).toString())
//                    .replace("{1}", SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getSalaryMonth()).toString()));
//        }
//        //撤回工资单
//        getSalarySendService(user).revokeSalaryBill(salaryAcctRecordId);
//        getTaxDeclarationService(user).delete(salaryAcctRecordPO);
//        // 更新薪资核算记录的状态
//        salaryAcctRecordPO.setStatus(SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue());
//        salaryAcctRecordPO.setUpdateTime(new Date());
//        getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);
//         记录日志
        String targetName = getLogTargetNameById(salaryAcctRecordPO.getId());
        LoggerContext<SalaryAcctRecordPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + salaryAcctRecordPO.getId());
        loggerContext.setTargetName(targetName);
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "重新核算"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "重新核算") + ": " + targetName);
        loggerContext.setNewValues(salaryAcctRecordPO);
        SalaryElogConfig.salaryAcctRecordLoggerTemplate.write(loggerContext);
    }


    private void reCalcOrBackCalc(SalaryAcctRecordPO salaryAcctRecordPO, boolean isReCalc) {
        // 如果薪资核算记录还未归档，不允许重新核算
        if (Objects.equals(salaryAcctRecordPO.getStatus(), SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98819, "薪资核算结果还未归档，可直接核算"));
        }
        // 税款所在年的日期范围（第一天～最后一天）
        LocalDateRange yearRange = SalaryDateUtil.localDate2YearRange(salaryAcctRecordPO.getSalaryMonth());
        if (Objects.isNull(yearRange)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(84026, "薪资所属月为空"));
        }
        // 查询税款所在年的该个税扣缴义务人所有薪资核算记录
        // 获取账套所属个税扣缴义务人的核算记录
        SalarySobPO salarySobPO = getSalarySobService(user).getById(salaryAcctRecordPO.getSalarySobId());
        Long taxAgentId = salarySobPO.getTaxAgentId();
        //查询扣缴义务人下的所有账套
        List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByTaxAgentId(taxAgentId);
        Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = listByTaxCycle(yearRange, salarySobIds);
        List<SalaryAcctRecordPO> selfSalaryAcctRecordPOS = filterByAuthority(salaryAcctRecordPOS);

        // 获取个税申报功能状态
        TaxDeclarationFunctionEnum taxDeclarationFunctionEnum = getSalarySysConfService(user).getTaxDeclaration();
        if (!taxDeclarationFunctionEnum.getValue().equals(TaxDeclarationFunctionEnum.CLOSURE.getValue())) {
            // 如果已经存在之后月份的薪资核算记录了，就不允许重新核算本月了
            SalaryAcctRecordPO afterSalaryAcctRecordPO = selfSalaryAcctRecordPOS.stream()
                    .filter(po -> po.getSalaryMonth().compareTo(salaryAcctRecordPO.getSalaryMonth()) > 0)
                    .findAny()
                    .orElse(null);
            if (Objects.nonNull(afterSalaryAcctRecordPO)) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(105826, "已经存在{0}的薪资核算记录了，不能重新核算{1}的薪资了")
                        .replace("{0}", SalaryDateUtil.localDate2YearMonth(afterSalaryAcctRecordPO.getSalaryMonth()).toString())
                        .replace("{1}", SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getSalaryMonth()).toString()));
            }
        }

        if (!isReCalc) {
            salaryAcctRecordPO.setBackCalcStatus(1);
//            salaryAcctRecordPO.setSuperId(salaryAcctRecordPO.getId());
//            salaryAcctRecordPO.setRootId(Objects.equals(salaryAcctRecordPO.getRootId(), 0L) ? salaryAcctRecordPO.getId() : salaryAcctRecordPO.getRootId());
        }

        // 保存回算前的薪资核算结果
        if (!isReCalc) {
            getSalaryAcctResultService(user).reCalc(salaryAcctRecordPO.getId());
        }
        // 撤回工资单
        getSalarySendService(user).revokeSalaryBill(salaryAcctRecordPO);

        // 重新核算或者回算时，若本次薪资核算记录已经申报了，则本次薪资核算记录下的所有个税扣缴义务人在相同税款所属期内的所有薪资核算记录的状态都应该从已申报变更为已归档
        // 过滤获取所在税款所属期内该个税扣缴义务人所有的薪资核算记录ID
        List<Long> needUpdateSalaryAcctRecordIds = selfSalaryAcctRecordPOS.stream().filter(po -> po.getTaxCycle().equals(salaryAcctRecordPO.getTaxCycle()))
                .map(SalaryAcctRecordPO::getId).collect(Collectors.toList());
        if (Objects.equals(salaryAcctRecordPO.getStatus(), SalaryAcctRecordStatusEnum.DECLARED.getValue())) {
            if (needUpdateSalaryAcctRecordIds != null && needUpdateSalaryAcctRecordIds.size() > 0) {
                // 更新薪资核算记录的状态
                updateStatusByIds(needUpdateSalaryAcctRecordIds, SalaryAcctRecordStatusEnum.ARCHIVED);
            }
            // 删除个税申报表及往期累计情况
            getTaxDeclarationService(user).delete(salaryAcctRecordPO);
        }

        // 更新薪资核算记录的状态
        salaryAcctRecordPO.setStatus(SalaryAcctRecordStatusEnum.NOT_ARCHIVED.getValue());
        salaryAcctRecordPO.setUpdateTime(new Date());
        getSalaryAcctRecordMapper().updateIgnoreNull(salaryAcctRecordPO);

        //删除报表缓存
        getSalaryStatisticsReportService(user).removeReportCache();
    }


    @Override
    public Integer hasConsolidatedTax(Long id) {
        // 查询合并计税的其他薪资核算记录
        List<SalaryAcctRecordPO> otherSalaryAcctRecordPOS = listById4OtherConsolidatedTax(id);
        if (CollectionUtils.isEmpty(otherSalaryAcctRecordPOS)) {
            return NumberUtils.INTEGER_ZERO;
        }
        // 查询本次核算的薪资核算人员
        List<SalaryAcctEmployeePO> salaryAcctEmployeePOS = getSalaryAcctEmployeeService(user).listBySalaryAcctRecordId(id);
        // 查询其他核算记录中的薪资核算人员
        Set<Long> otherSalaryAcctRecordIds = SalaryEntityUtil.properties(otherSalaryAcctRecordPOS, SalaryAcctRecordPO::getId);
        List<SalaryAcctEmployeePO> otherSalaryAcctEmployeePOS = getSalaryAcctEmployeeService(user).listBySalaryAcctRecordIds(otherSalaryAcctRecordIds);
        // 有其他核算记录，需要进一步判断本次核算的人员中是否存在合并计税
        Set<String> keySet = SalaryEntityUtil.properties(otherSalaryAcctEmployeePOS, salaryAcctEmployeePO -> salaryAcctEmployeePO.getEmployeeId() + "-" + salaryAcctEmployeePO.getTaxAgentId());
        boolean hasConsolidatedTax = salaryAcctEmployeePOS.stream().anyMatch(salaryAcctEmployeePO -> keySet.contains(salaryAcctEmployeePO.getEmployeeId() + "-" + salaryAcctEmployeePO.getTaxAgentId()));
        if (hasConsolidatedTax) {
            return NumberUtils.INTEGER_ONE;
        }
        return NumberUtils.INTEGER_ZERO;
    }

    @Override
    public String getLogTargetNameById(Long id) {
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getById(id);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 查询账套
        SalarySobPO salarySobPO = getSalarySobService(user).getById(salaryAcctRecordPO.getSalarySobId());
        if (Objects.isNull(salarySobPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98769, "薪资账套不存在或已被删除"));
        }
        return salarySobPO.getName() + SalaryDateUtil.localDate2YearMonth(salaryAcctRecordPO.getSalaryMonth());
    }

    @Override
    public List<SalaryAcctRecordPO> listByStatus(SalaryAcctRecordStatusEnum status) {
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().status(status.getValue()).build());
    }

    @Override
    public List<SalaryAcctRecordPO> listByStatusAndEmployeeId(SalaryAcctRecordStatusEnum status, Long employeeId) {
        return getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().status(status.getValue()).creator(employeeId).build());
    }

    @Override
    public void updateLockSalaryItemIds(SalaryAcctRecordPO salaryAcctRecord) {
        getSalaryAcctRecordMapper().updateLockSalaryItemIds(salaryAcctRecord);
    }

    @Override
    public void backCalculate(Long salaryAcctRecordId) {
        // 查询薪资核算记录
        SalaryAcctRecordPO salaryAcctRecordPO = getById(salaryAcctRecordId);
        if (Objects.isNull(salaryAcctRecordPO)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(98747, "薪资核算记录不存在或已被删除"));
        }
        // 获取该账套该月核算的所有记录
        List<SalaryAcctRecordPO> salaryAcctRecordPOS = getSalaryAcctRecordMapper().listSome(SalaryAcctRecordPO.builder().salaryMonth(salaryAcctRecordPO.getSalaryMonth()).salarySobId(salaryAcctRecordPO.getSalarySobId()).deleteType(0).build());
        // 只有该账套在此月的最后一次核算才能进行回算
        if (!salaryAcctRecordPO.getAcctTimes().equals(salaryAcctRecordPOS.size())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "只有核算次数为最后一次时，才能进行回算"));
        }
        // 只有正常核算全部发送完才能进行回算
        SalarySendPO build = SalarySendPO.builder().salaryAccountingId(salaryAcctRecordId).deleteType(0).build();
        List<SalarySendPO> salarySends = getSalarySendMapper().listSome(build);
        salarySends.stream().forEach(salarySend -> {
            if (salarySend.getSendNum() < salarySend.getSendTotal()) {
                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(139702, "正常核算工资单尚未全部发送完成，不能进行回算"));
            }
        });

        // 回算
        reCalcOrBackCalc(salaryAcctRecordPO, false);
    }

    @Override
    public List<SalaryAcctRecordPO> getBackCalcRecordByIds(Set<Long> salaryAcctIds) {
        if (CollectionUtils.isEmpty(salaryAcctIds)) {
            return Collections.emptyList();
        }
        return getSalaryAcctRecordMapper().getBackCalcRecordByIds(salaryAcctIds);
    }


    /**
     * 开启分权后需要判断是否能查看对应的薪资核算记录
     *
     * @param salaryAcctRecords
     * @return
     */
    private List<SalaryAcctRecordPO> filterByAuthority(List<SalaryAcctRecordPO> salaryAcctRecords) {
        if (CollectionUtils.isEmpty(salaryAcctRecords)) {
            return salaryAcctRecords;
        }
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        //开启分权
        if (openDevolution) {
            List<SalarySobPO> salarySobPOS = getSalarySobService(user).listByAdmin();
            Set<Long> salarySobIds = SalaryEntityUtil.properties(salarySobPOS, SalarySobPO::getId);
            return salaryAcctRecords.stream().filter(record -> salarySobIds.contains(record.getSalarySobId())).collect(Collectors.toList());
        }

        return salaryAcctRecords;
    }

    @Override
    public List<SalaryAcctResultPO> listBySalaryAcctEmpId(Long salaryAcctEmpId) {
        return getSalaryAcctResultService(user).listBySalaryAcctEmployeeId(salaryAcctEmpId);
    }

    @Override
    public List<SalaryAcctRecordPO> listSome(SalaryAcctRecordPO po) {
        return getSalaryAcctRecordMapper().listSome(po);
    }
}
