package com.engine.salary.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.api.browser.bean.SearchConditionGroup;
import com.api.browser.bean.SearchConditionItem;
import com.api.browser.bean.SearchConditionOption;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.cloudstore.dev.api.util.Util_DataCache;
import com.cloudstore.eccom.pc.table.*;
import com.cloudstore.eccom.result.WeaResultMsg;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.biz.TaxAgentBiz;
import com.engine.salary.cache.SalaryCacheKey;
import com.engine.salary.component.SalaryWeaTable;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.constant.SalaryItemConstant;
import com.engine.salary.encrypt.EncryptUtil;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.progress.ProgressDTO;
import com.engine.salary.entity.siaccount.bo.InsuranceAccountBO;
import com.engine.salary.entity.siaccount.dto.*;
import com.engine.salary.entity.siaccount.param.*;
import com.engine.salary.entity.siaccount.po.*;
import com.engine.salary.entity.siarchives.po.*;
import com.engine.salary.entity.sicategory.po.ICategoryPO;
import com.engine.salary.entity.siexport.param.InsuranceExportParam;
import com.engine.salary.entity.siexport.po.AccountExportPO;
import com.engine.salary.entity.sischeme.po.InsuranceSchemeDetailPO;
import com.engine.salary.entity.sischeme.po.InsuranceSchemePO;
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.siaccount.*;
import com.engine.salary.enums.sicategory.*;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.InsuranceExportMapper;
import com.engine.salary.mapper.datacollection.EmployMapper;
import com.engine.salary.mapper.siaccount.*;
import com.engine.salary.mapper.siarchives.FundSchemeMapper;
import com.engine.salary.mapper.siarchives.InsuranceBaseInfoMapper;
import com.engine.salary.mapper.siarchives.OtherSchemeMapper;
import com.engine.salary.mapper.siarchives.SocialSchemeMapper;
import com.engine.salary.mapper.sicategory.ICategoryMapper;
import com.engine.salary.mapper.sischeme.InsuranceSchemeDetailMapper;
import com.engine.salary.mapper.sischeme.InsuranceSchemeMapper;
import com.engine.salary.mapper.sys.SalarySysConfMapper;
import com.engine.salary.mapper.taxagent.TaxAgentMapper;
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.SalaryAcctEmployeeRuleEnum;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.*;
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.ExcelUtil;
import com.engine.salary.util.excel.ExcelUtilPlus;
import com.engine.salary.util.page.Column;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.engine.salary.util.valid.ValidUtil;
import com.engine.salary.wrapper.SalaryFormulaWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.mzlion.core.utils.BeanUtils;
import com.wbi.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import weaver.file.ImageFileManager;
import weaver.general.Util;
import weaver.hrm.User;

import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

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


/**
 * @Author weaver_cl
 * @Description:
 * @Date 2022/4/11
 * @Version V1.0
 **/
@Slf4j
public class SIAccountServiceImpl extends Service implements SIAccountService {


//    private SIArchivesBiz siArchivesBiz = new SIArchivesBiz();

    private EncryptUtil encryptUtil = new EncryptUtil();

    public RecordsBuildService getService(User user) {
        return ServiceUtil.getService(RecordsBuildServiceImpl.class, user);
    }

//    public SIAccountBiz getSiAccountBiz(User user) {
//        return ServiceUtil.getService(SIAccountBiz.class, user);
//    }

    public ColumnBuildService getColumnBuildService(User user) {
        return ServiceUtil.getService(ColumnBuildServiceImpl.class, user);
    }

    public SICategoryService getSICategoryService(User user) {
        return ServiceUtil.getService(SICategoryServiceImpl.class, user);
    }

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

    private InsuranceAccountBatchMapper getInsuranceAccountBatchMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountBatchMapper.class);
    }

    private InsuranceAccountDetailMapper getInsuranceAccountDetailMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountDetailMapper.class);
    }

    private ExcelInsuranceDetailMapper getExcelInsuranceDetailMapper() {
        return MapperProxyFactory.getProxy(ExcelInsuranceDetailMapper.class);
    }

    private SalaryItemService getSalaryItemService(User user) {
        return (SalaryItemService) ServiceUtil.getService(SalaryItemServiceImpl.class, user);
    }

    private TaxAgentMapper getTaxAgentMapper() {
        return MapperProxyFactory.getProxy(TaxAgentMapper.class);
    }

//    SICategoryBiz siCategoryBiz = new SICategoryBiz();

    private SalarySysConfMapper getSalarySysConfMapper() {
        return SqlProxyHandle.getProxy(SalarySysConfMapper.class);
    }

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

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

    private InsuranceSchemeMapper getInsuranceSchemeMapper() {
        return MapperProxyFactory.getProxy(InsuranceSchemeMapper.class);
    }

    private InsuranceBaseInfoMapper getInsuranceBaseInfoMapper() {
        return MapperProxyFactory.getProxy(InsuranceBaseInfoMapper.class);
    }

    private SocialSchemeMapper getSocialSchemeMapper() {
        return MapperProxyFactory.getProxy(SocialSchemeMapper.class);
    }

    private FundSchemeMapper getFundSchemeMapper() {
        return MapperProxyFactory.getProxy(FundSchemeMapper.class);
    }

    private OtherSchemeMapper getOtherSchemeMapper() {
        return MapperProxyFactory.getProxy(OtherSchemeMapper.class);
    }

    private TaxAgentBiz taxAgentBiz = new TaxAgentBiz();

    private ICategoryMapper getICategoryMapper() {
        return MapperProxyFactory.getProxy(ICategoryMapper.class);
    }

    private InsuranceAccountInspectMapper getInsuranceAccountInspectMapper() {
        return MapperProxyFactory.getProxy(InsuranceAccountInspectMapper.class);
    }

    private InsuranceExportMapper getInsuranceExportMapper() {
        return MapperProxyFactory.getProxy(InsuranceExportMapper.class);
    }

    private InsuranceSchemeDetailMapper getInsuranceSchemeDetailMapper() {
        return MapperProxyFactory.getProxy(InsuranceSchemeDetailMapper.class);
    }

    private SalaryFormulaWrapper getSalaryFormulaWrapper(User user) {
        return (SalaryFormulaWrapper) ServiceUtil.getService(SalaryFormulaWrapper.class, user);
    }

    public SIExportService getSIExportService(User user) {
        return ServiceUtil.getService(SIExportServiceImpl.class, user);
    }

    private SIBalanceService getSIBalanceService(User user) {
        return (SIBalanceService) ServiceUtil.getService(SIBalanceServiceImpl.class, user);
    }

    private ProgressService getSalaryAcctProgressService(User user) {
        return ServiceUtil.getService(ProgressServiceImpl.class, user);
    }

    private SIAccountDetailTempMapper getSIAccountDetailTempMapper() {
        return MapperProxyFactory.getProxy(SIAccountDetailTempMapper.class);
    }

    private InsuranceCompensationMapper getInsuranceCompensationMapper() {
        return MapperProxyFactory.getProxy(InsuranceCompensationMapper.class);
    }

    private SIAccountUtilMapper getSIAccountUtilMapper() {
        return MapperProxyFactory.getProxy(SIAccountUtilMapper.class);
    }

    public SIArchivesService getSIArchivesService(User user) {
        return ServiceUtil.getService(SIArchivesServiceImpl.class, user);
    }

    private EmployMapper getEmployMapper() {
        return MapperProxyFactory.getProxy(EmployMapper.class);
    }

    @Override
    public Map<String, Object> listPage(InsuranceAccountBatchParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

        List<Long> paymentOrganizationIds = queryParam.getTaxAgents();
        // 分权逻辑
        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        if (needAuth) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgents((long) user.getUID());
            List<Long> taxAgents = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgents)) {
                //防止普通用户查询
                queryParam.setTaxAgents(Collections.singletonList(-1L));
            } else {
                if (paymentOrganizationIds != null && paymentOrganizationIds.size() > 0) {
                    taxAgents.retainAll(paymentOrganizationIds);
                }
                queryParam.setTaxAgents(taxAgents);
            }
        }

        //福利台账列表
//        PageInfo<InsuranceAccountBatchPO> pageInfo = getSiAccountBiz(user).listPage(queryParam);
        PageInfo<InsuranceAccountBatchPO> pageInfo = siBatchListPage(queryParam);
        Collection<InsuranceAccountBatchPO> insuranceAccountBatchPOS = pageInfo.getList();

        List<InsuranceAccountBatchListDTO> insuranceAccountBatchListDTOS = InsuranceAccountBO.buildAccountBatchDTOList(insuranceAccountBatchPOS);
        PageInfo<InsuranceAccountBatchListDTO> pageInfos = new PageInfo<>(insuranceAccountBatchListDTOS, InsuranceAccountBatchListDTO.class);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(queryParam.getCurrent());
        pageInfos.setPageSize(queryParam.getPageSize());


        List<Map<Integer, List<Permission>>> operatesPermission = new ArrayList<>();

        SalaryWeaTable<InsuranceAccountBatchListDTO> table = new SalaryWeaTable<>(user, InsuranceAccountBatchListDTO.class);
        List<Column> columns = pageInfos.getColumns();
        List<WeaTableColumn> weaTableColumn = columns.stream().map(v -> new WeaTableColumn("100", v.getTitle(), v.getKey())).collect(Collectors.toList());

        table.setColumns(weaTableColumn);

        //table.getColumns().get(0).setFixed("left");
//        for (int i = 0; i < insuranceAccountBatchListDTOS.size(); i++) {
//            InsuranceAccountBatchListDTO insuranceAccountBatchListDTO = insuranceAccountBatchListDTOS.get(i);
//            if (Objects.equals(insuranceAccountBatchListDTO.getBillStatus(), BillStatusEnum.ARCHIVED.getDefaultLabel())) {
//                table.getOperates().getOperate().get(i).getIndex();
//
//                resultTable.getOperatesPermission().get(i).get(0).setVisible(false);
//                resultTable.getOperatesPermission().get(i).get(1).setVisible(false);
//                resultTable.getOperatesPermission().get(i).get(2).setVisible(false);
//                resultTable.getOperatesPermission().get(i).get(3).setVisible(false);
//                resultTable.getOperates().get(4).setOuter(true);
//            }
//            if (Objects.equals(insuranceAccountBatchListDTO.getBillStatus(), BillStatusEnum.NOT_ARCHIVED.getDefaultLabel())) {
//                resultTable.getOperatesPermission().get(i).get(4).setVisible(false);
//                List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = siAccountInspectService.listByBillMonth(insuranceAccountBatchListDTO.getBillMonth(), tenantKey);
//                if (CollectionUtils.isEmpty(insuranceAccountInspectPOS)) {
//                    resultTable.getOperatesPermission().get(i).get(2).setVisible(false);
//                }
//            }
//        }

        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("pageInfo", pageInfos);
        datas.put("operatesPermission", operatesPermission);
        datas.put("dataKey", result.getResultMap());
        return datas;

//        WeaTable<InsuranceAccountBatchListDTO> resultTable = FormatManager.<InsuranceAccountBatchListDTO>getInstance()
//                .genTable(InsuranceAccountBatchListDTO.class, insuranceAccountBatchListDTOPage);
//
//        resultTable.getOperates().forEach(e -> {
//            if (e.getIndex() == 0) {
//                e.setOuter(true);
//            }
//        });

//        resultTable.setModule("hrmsalary");
//        resultTable.getColumns().get(0).setFixed("left");
//        return WeaResult.success(resultTable);

    }

    @Override
    public Map<String, Object> listCommonPage(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

        //正常缴纳列表
//        PageInfo<InsuranceAccountDetailPO> pageInfo = getSiAccountBiz(user).listCommonPage(queryParam);
        PageInfo<InsuranceAccountDetailPO> pageInfo = siBatchListCommonPage(queryParam);
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = pageInfo.getList();

        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(insuranceAccountDetailPOS, employeeId);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(records);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(queryParam.getCurrent());
        pageInfos.setPageSize(queryParam.getPageSize());


        //动态列组装
        List<WeaTableColumn> weaTableColumn = getColumnBuildService(user).buildCommonColumnsWithStyle(insuranceAccountDetailPOS, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, queryParam.getPaymentStatus());

        WeaTable table = new WeaTable();
        table.setPageUID(UUID.randomUUID().toString());
        table.setColumns(weaTableColumn);
        List<Column> columns = weaTableColumn.stream().map(v -> new Column(v.getText(), v.getColumn(), v.getColumn())).collect(Collectors.toList());
        pageInfos.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("pageInfo", pageInfos);
        //datas.put("dataKey",result.getResultMap());
        return datas;
    }


    @Override
    public Map<String, Object> listCommonPageByName(InsuranceAccountDetailParam queryParam) {
        //增加查询参数userName
        if (StringUtils.isNotBlank(queryParam.getUserName())) {
            queryParam.setUserName(queryParam.getUserName());
        }
        return listCommonPage(queryParam);
    }

    @Override
    public Map<String, Object> listSupplementaryPage(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

//        //过滤出福利档案基础信息表中runStatus为正在缴纳和待减员的人员
//        List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
//        List<Long> canAccountIds = baseInfoPOList.stream()
//                .filter(f->f.getPaymentOrganization().toString().equals(queryParam.getPaymentOrganization())
//                        && (f.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()) || f.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue())))
//                .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
//                .collect(Collectors.toList());
//        queryParam.setEmployeeIds(canAccountIds);

        //补缴缴纳列表
        queryParam.setPaymentStatus(PaymentStatusEnum.REPAIR.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        PageInfo<InsuranceAccountDetailPO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(),queryParam.getPageSize(),
                list, InsuranceAccountDetailPO.class);
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = pageInfo.getList();
        encryptUtil.decryptList(insuranceAccountDetailPOS, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(insuranceAccountDetailPOS, employeeId);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(records);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(queryParam.getCurrent());
        pageInfos.setPageSize(queryParam.getPageSize());


        //动态列组装
        List<WeaTableColumn> weaTableColumn = getColumnBuildService(user).buildCommonColumnsWithStyle(insuranceAccountDetailPOS, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, queryParam.getPaymentStatus());

        SalaryWeaTable<InsuranceAccountDetailPO> table = new SalaryWeaTable<>(user, InsuranceAccountDetailPO.class);
        table.setColumns(weaTableColumn);
        List<Column> columns = weaTableColumn.stream().map(v -> new Column(v.getText(), v.getColumn(), v.getColumn())).collect(Collectors.toList());
        pageInfos.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("pageInfo", pageInfos);
        //datas.put("dataKey",result.getResultMap());
        return datas;
    }


    @Override
    public Map<String, Object> supplementaryByNameList(InsuranceAccountDetailParam queryParam) {
        //增加查询参数userName
        if (StringUtils.isNotBlank(queryParam.getUserName())) {
            queryParam.setUserName(queryParam.getUserName());
        }
        return listSupplementaryPage(queryParam);
    }

    @Override
    public Map<String, Object> listRecessionPage(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

        // 分权逻辑
        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        if (needAuth) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgents((long) user.getUID());
            List<Long> taxAgents = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgents)) {
                //防止普通用户查询
                queryParam.setTaxAgents(Collections.singletonList(-1L));
            } else {
                queryParam.setTaxAgents(taxAgents);
            }
        }

        //退差列表
        queryParam.setPaymentStatus(PaymentStatusEnum.RECESSION.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        PageInfo<InsuranceAccountDetailPO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(),queryParam.getPageSize(),
                list, InsuranceAccountDetailPO.class);
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = pageInfo.getList();
        encryptUtil.decryptList(insuranceAccountDetailPOS, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(insuranceAccountDetailPOS, employeeId);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(records);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(queryParam.getCurrent());
        pageInfos.setPageSize(queryParam.getPageSize());


        //动态列组装
        List<WeaTableColumn> weaTableColumn = getColumnBuildService(user).buildCommonColumnsWithStyle(insuranceAccountDetailPOS, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, queryParam.getPaymentStatus());

        SalaryWeaTable<InsuranceAccountDetailPO> table = new SalaryWeaTable<>(user, InsuranceAccountDetailPO.class);
        table.setColumns(weaTableColumn);
        List<Column> columns = weaTableColumn.stream().map(v -> new Column(v.getText(), v.getColumn(), v.getColumn())).collect(Collectors.toList());
        pageInfos.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("pageInfo", pageInfos);
        //datas.put("dataKey",result.getResultMap());
        return datas;
    }

    @Override
    public Map<String, Object> listBalancePage(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

        // 分权逻辑
        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        if (needAuth) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgents((long) user.getUID());
            List<Long> taxAgents = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgents)) {
                //防止普通用户查询
                queryParam.setTaxAgents(Collections.singletonList(-1L));
            } else {
                queryParam.setTaxAgents(taxAgents);
            }
        }

        //补差列表
        queryParam.setPaymentStatus(PaymentStatusEnum.BALANCE.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        PageInfo<InsuranceAccountDetailPO> pageInfo = new PageInfo<>(list, InsuranceAccountDetailPO.class);
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = pageInfo.getList();
        encryptUtil.decryptList(insuranceAccountDetailPOS, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(insuranceAccountDetailPOS, employeeId);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(records);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(queryParam.getCurrent());
        pageInfos.setPageSize(queryParam.getPageSize());


        //动态列组装
        List<WeaTableColumn> weaTableColumn = getColumnBuildService(user).buildCommonColumnsWithStyle(insuranceAccountDetailPOS, employeeId, SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY, queryParam.getPaymentStatus());

        SalaryWeaTable<InsuranceAccountDetailPO> table = new SalaryWeaTable<>(user, InsuranceAccountDetailPO.class);
        table.setColumns(weaTableColumn);
        List<Column> columns = weaTableColumn.stream().map(v -> new Column(v.getText(), v.getColumn(), v.getColumn())).collect(Collectors.toList());
        pageInfos.setColumns(columns);


        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("pageInfo", pageInfos);
        //datas.put("dataKey",result.getResultMap());
        return datas;
    }

    @Override
    public Map<String, Object> getForm(Map<String, Object> params) {
        Map<String, Object> apidatas = new HashMap<>();

        //条件组
        List<SearchConditionGroup> addGroups = new ArrayList<>();
        List<SearchConditionItem> conditionItems = new ArrayList<>();
        SearchConditionItem datePickerItem = SalaryFormItemUtil.datePickerItem(user, 2, 16, true, 2, "账单月份", "billMonth");
        String minDate = SalaryDateUtil.getYearMonth(-1, 0);
        String maxDate = SalaryDateUtil.getYearMonth(0, 6);
        datePickerItem.setOtherParams(new HashMap<>());
        datePickerItem.getOtherParams().put("minDate", minDate);
        datePickerItem.getOtherParams().put("maxDate", maxDate);

        List<InsuranceAccountBatchPO> billMonthList = getInsuranceAccountBatchMapper().listByTimeRange(minDate, maxDate);
        encryptUtil.decryptList(billMonthList, InsuranceAccountBatchPO.class);
        if (CollectionUtils.isEmpty(billMonthList)) {
            datePickerItem.getOtherParams().put("disabledData", Collections.emptyList());
        } else {
            datePickerItem.getOtherParams().put("disabledData", billMonthList.stream().map(InsuranceAccountBatchPO::getBillMonth).collect(Collectors.toList()));
        }
        datePickerItem.getOtherParams().put("type", "month");
        datePickerItem.getOtherParams().put("format", "YYYY-MM");
        datePickerItem.getOtherParams().put("showFormat", "YYYY-MM");
        conditionItems.add(datePickerItem);

        SearchConditionItem textareaItem = SalaryFormItemUtil.textareaItem(user, 2, 16, true, 2, 60, "备注", "remarks");
        conditionItems.add(textareaItem);
        addGroups.add(new SearchConditionGroup("常用条件", true, conditionItems));

        apidatas.put("billMonth", SalaryDateUtil.getYearMonth(0, 0));

        apidatas.put("condition", addGroups);

        return apidatas;
    }

    @Override
    public String save(AccountParam param) {
//        ValidUtil.doValidator(param);
//
//        Long employeeId = (long) user.getUID();
//        String lastName = user.getLastname();
//        return getSiAccountBiz(user).save(param.isFlag(), param, employeeId, lastName);
        return saveAndFile(param);
    }

    @Override
    public void commonAccount(SaveCommonAccountParam param) {
//        ValidUtil.doValidator(param);
//
//        Long employeeId = (long) user.getUID();
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).saveCommonAccount(param, employeeId, currentUserName);
        siSaveCommonAccount(param);
    }

    @Override
    public void delete(AccountParam accountParam) {
        Long employeeId = (long) user.getUID();
//        getSiAccountBiz(user).delete(accountParam, employeeId);
        siDelete(accountParam);
    }

    @Override
    public void saveCommonAccount(SaveCommonAccountParam accountParam) {
//        Long employeeId = (long) user.getUID();
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).saveCommonAccount(accountParam, employeeId, currentUserName);
        siSaveCommonAccount(accountParam);
    }

    /**
     * 福利台账正常缴纳页-核算
     */
    public void siSaveCommonAccount(SaveCommonAccountParam param) {
        ValidUtil.doValidator(param);

        List<Long> collect;
        SalaryAssert.notEmpty(param.getIncludes(), SalaryI18nUtil.getI18nLabel(100466, "参数为空"));
        SalaryAssert.notNull(param.getBillMonth(), SalaryI18nUtil.getI18nLabel(100467, "账单月为空"));
        if (CollectionUtils.isNotEmpty(param.getExcludes())) {
            collect = param.getIncludes().stream().filter(item -> !param.getExcludes().contains(item)).collect(Collectors.toList());
        } else {
            collect = param.getIncludes();
        }
        SalaryAssert.notEmpty(collect, SalaryI18nUtil.getI18nLabel(99920, "无核算人员"));
        AccountParam accountParam = new AccountParam();
        accountParam.setBillMonth(param.getBillMonth());
        accountParam.setIds(collect);
        siAccounting(accountParam);
    }

    @Override
    public void saveSupplementaryAccount(SaveSupplementaryAccountParam saveSupplementaryAccountParam) {
        ValidUtil.doValidator(saveSupplementaryAccountParam);

//        Long employeeId = (long) user.getUID();
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).saveSupplementaryAccount(saveSupplementaryAccountParam, employeeId, currentUserName);
        siSaveSupplementaryAccount(saveSupplementaryAccountParam);
    }

    @Override
    public void deleteCommonAccount(SaveCommonAccountParam param) {
        ValidUtil.doValidator(param);
//        Long employeeId = (long) user.getUID();
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).deleteCommonAccount(param, employeeId, currentUserName);
        siDeleteCommonAccount(param);
    }

    @Override
    public void deleteSupplementaryAccount(SaveCommonAccountParam param) {
//        Long employeeId = (long) user.getUID();
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).deleteSupplementaryAccount(supplementAccountBaseParams, employeeId, currentUserName);
        siDeleteSupplementaryAccount(param);
    }

    @Override
    public void file(AccountParam accountParam) {
//        Long employeeId = (long) user.getUID();
//        String billMonth = accountParam.getBillMonth();
//        getSiAccountBiz(user).file(billMonth, employeeId, accountParam.getPaymentOrganization());
        siFile(accountParam.getBillMonth(), accountParam.getPaymentOrganization());
    }

    @Override
    public void unconfirmed(Collection<Long> ids) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = getInsuranceAccountInspectMapper().getByInspectStatusAndIds(InspectStatusEnum.COMFORED.getValue(), ids);

        if (CollectionUtils.isNotEmpty(insuranceAccountInspectPOS)) {
            getInsuranceAccountDetailMapper().batchUnConfirmedInspectDetails(insuranceAccountInspectPOS.stream().map(InsuranceAccountInspectPO::getId).collect(Collectors.toList()));
        }
    }


    @Override
    public Map<String, Boolean> buttonCheck(String billMonth) {
        Map<String, Boolean> result = new HashMap<>();
        List<InsuranceAccountInspectPO> list = getInsuranceAccountInspectMapper().getByInspectStatusAndBillMonth(InspectStatusEnum.IGNORE.getValue(), billMonth);
        if (CollectionUtils.isEmpty(list)) {
            result.put("displayFlag", false);
            return result;
        }
        result.put("displayFlag", true);
        return result;
    }

    @Override
    public void ignore(Collection<Long> ids) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = getInsuranceAccountInspectMapper().getByInspectStatusAndIds(InspectStatusEnum.IGNORE.getValue(), ids);

        if (CollectionUtils.isNotEmpty(insuranceAccountInspectPOS)) {
            getInsuranceAccountDetailMapper().batchIgnoreInspectDetails(insuranceAccountInspectPOS.stream().map(InsuranceAccountInspectPO::getId).collect(Collectors.toList()));
        }
    }

    @Override
    public InsuranceAccountTabDTO tabList(AccountParam build) {
        InsuranceAccountTabDTO insuranceAccountTabDTO = InsuranceAccountTabDTO.builder().build();
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(build.getBillMonth(), build.getPaymentOrganization());
        insuranceAccountBatchPO = encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        boolean isShow = false;
        if (insuranceAccountBatchPO == null || insuranceAccountBatchPO.getBillStatus() == BillStatusEnum.NOT_ARCHIVED.getValue()) {
            isShow = true;
        }
        if (insuranceAccountBatchPO != null) {
            insuranceAccountTabDTO.setRemarks(insuranceAccountBatchPO.getRemarks());
        }
        List<Map<String, Object>> tabList = new ArrayList<>();
        Map<String, Object> common = new HashMap<>();
        common.put("id", "1");
        common.put("content", SalaryI18nUtil.getI18nLabel(92265, "正常缴纳"));
        tabList.add(common);
        if (isShow) {
            Map<String, Object> change = new HashMap<>();
            change.put("id", "2");
            change.put("content", SalaryI18nUtil.getI18nLabel(100509, "异动清单"));
            tabList.add(change);
        }
        Map<String, Object> repair = new HashMap<>();
        repair.put("id", "3");
        repair.put("content", SalaryI18nUtil.getI18nLabel(92267, "补缴"));
        tabList.add(repair);

        Map<String, Object> overView = new HashMap<>();
        overView.put("id", "4");
        overView.put("content", SalaryI18nUtil.getI18nLabel(99927, "总览"));
        tabList.add(overView);

        Map<String, Object> recession = new HashMap<>();
        recession.put("id", "5");
        recession.put("content", SalaryI18nUtil.getI18nLabel(92270, "退差"));
        tabList.add(recession);

        Map<String, Object> balance = new HashMap<>();
        balance.put("id", "6");
        balance.put("content", SalaryI18nUtil.getI18nLabel(92271, "补差"));
        tabList.add(balance);

        insuranceAccountTabDTO.setTabList(tabList);
        insuranceAccountTabDTO.setShow(isShow);
        insuranceAccountTabDTO.setBillMonth(build.getBillMonth());
        return insuranceAccountTabDTO;
    }

    @Override
    public Map<String, Object> changeList(InsuranceAccountDetailParam param) {
        Map<String, Object> datas = new HashMap<>();
        Long employeeId = (long) user.getUID();
        List<InsuranceArchivesEmployeePO> insuranceArchivesEmployeePOS = getInsuranceAccountDetailMapper().changeList(param.getUserName());
        PageInfo<InsuranceArchivesEmployeePO> pageInfo = SalaryPageUtil.buildPage(param.getCurrent(), param.getPageSize(),
                insuranceArchivesEmployeePOS, InsuranceArchivesEmployeePO.class);

//        List<Map<String, Object>> records = siArchivesBiz.buildTableData(insuranceArchivesEmployeePOS);
        List<Map<String, Object>> records = getSIArchivesService(user).buildTableData(insuranceArchivesEmployeePOS);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(records);
        pageInfos.setTotal(pageInfo.getTotal());
        pageInfos.setPageNum(param.getCurrent());
        pageInfos.setPageSize(param.getPageSize());

//        List<WeaTableColumn> weaTableColumns = siArchivesBiz.buildWeaTableColumns(insuranceArchivesEmployeePOS, employeeId);
        List<WeaTableColumn> weaTableColumns = getSIArchivesService(user).buildWeaTableColumns(insuranceArchivesEmployeePOS);

        WeaTable table = new WeaTable();
        table.setPageUID(UUID.randomUUID().toString());
        table.setColumns(weaTableColumns);
        table.setTableType(WeaTableType.CHECKBOX);
        WeaTableOperates weaTableOperates = new WeaTableOperates();
        WeaTableOperate weaTableOperate = new WeaTableOperate();
        weaTableOperate.setIndex("0");
        weaTableOperate.setText("移除");
        WeaTableOperate weaTableOperate1 = new WeaTableOperate();
        weaTableOperate1.setIndex("1");
        weaTableOperate1.setText("添加");
        table.setOperates(weaTableOperates);

        List<List<Permission>> permissions = new ArrayList<>();
        for (int i = 0; i < records.size(); i++) {
            List<Permission> permission = new ArrayList<>();
            if (UserStatusEnum.DEPARTURE.getDefaultLabel().equals(records.get(i).get("status"))) {
                permission.add(new Permission(true, false));
                permission.add(new Permission(false, false));
                permissions.add(permission);
            }
            if (UserStatusEnum.DEPARTURE.getDefaultLabel().equals(records.get(i).get("status"))) {
                permission.add(new Permission(false, false));
                permission.add(new Permission(true, false));
                permissions.add(permission);
            }
        }

        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("permissions", permissions);
        datas.put("pageInfo", pageInfos);
        datas.put("dataKey", result.getResultMap());
        return datas;
    }

    @Override
    public void accountInspect(InspectAccountParam param) {
//        Long employeeId = (long) user.getUID();
        ValidUtil.doValidator(param);
//        String currentUserName = user.getLastname();
//        getSiAccountBiz(user).accountInspect(param.getIds(), param.getBillMonth(), employeeId, currentUserName, param.getPaymentOrganization());
        accountInspect(param.getIds(), param.getBillMonth(), param.getPaymentOrganization());
    }

    @Override
    public Map<String, Object> getInspectTable(InsuranceAccountDetailParam param) {
        Map<String, Object> datas = new HashMap<>();

        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = getInsuranceAccountInspectMapper().getByBillMonth(param.getBillMonth());
        List<Map<String, Object>> records = getService(user).buildInspectRecords(insuranceAccountInspectPOS, Long.valueOf(param.getPaymentOrganization()));
        List<Map<String, Object>> paged = SalaryPageUtil.subList(param.getCurrent(), param.getPageSize(), records);
        PageInfo<Map<String, Object>> pageInfos = new PageInfo<>(paged);
        pageInfos.setTotal(records.size());
        pageInfos.setPageNum(param.getCurrent());
        pageInfos.setPageSize(param.getPageSize());

        List<WeaTableColumn> weaTableColumns = getColumnBuildService(user).buildInspectColumns(insuranceAccountInspectPOS, Long.valueOf(param.getPaymentOrganization()));
        WeaTable table = new WeaTable();
        table.setPageUID(UUID.randomUUID().toString());
        table.setColumns(weaTableColumns);
        table.setTableType(WeaTableType.CHECKBOX);
        WeaTableOperates weaTableOperates = new WeaTableOperates();
        WeaTableOperate weaTableOperate = new WeaTableOperate();
        weaTableOperate.setIndex("0");
        weaTableOperate.setText("忽略");
        WeaTableOperate weaTableOperate1 = new WeaTableOperate();
        weaTableOperate1.setIndex("1");
        weaTableOperate1.setText("重置");
        table.setOperates(weaTableOperates);

        List<List<Permission>> permissions = new ArrayList<>();
        for (int i = 0; i < records.size(); i++) {
            List<Permission> permission = new ArrayList<>();
            Permission permissionCheckBox = new Permission();
            if (InspectStatusEnum.IGNORE.getValue() == records.get(i).get("inspectStatus")) {
                permissionCheckBox.setVisible(true);
                permissionCheckBox.setDisabled(false);
                permission.add(new Permission(true, false));
                permission.add(new Permission(false, true));
                permissions.add(permission);
            }
            if (InspectStatusEnum.COMFORED.getValue() == records.get(i).get("inspectStatus")) {
                permissionCheckBox.setVisible(true);
                permissionCheckBox.setDisabled(true);
                permission.add(new Permission(false, true));
                permission.add(new Permission(true, false));
                permissions.add(permission);
            }
        }

        WeaResultMsg result = new WeaResultMsg(false);
        result.putAll(table.makeDataResult());
        result.success();

        datas.put("permissions", permissions);
        datas.put("pageInfo", pageInfos);
        datas.put("dataKey", result.getResultMap());

        return datas;
    }

    @Override
    public Map<String, Object> getCommonForm(Map<String, Object> params) {
        Map<String, Object> apidatas = new HashMap<>();

        //条件组
        List<SearchConditionGroup> addGroups = new ArrayList<>();
        List<SearchConditionItem> conditionItems = new ArrayList<>();
        List<SearchConditionItem> conditionItem = new ArrayList<>();

        SearchConditionItem includes = SalaryFormItemUtil.browserItem(user, 18, 12, 2, true, "对象", "required", "17", "includes");
        conditionItems.add(includes);
        SearchConditionItem excludes = SalaryFormItemUtil.browserItem(user, 18, 12, 2, true, "选择人员", "required", "17", "excludes");
        conditionItem.add(excludes);
        addGroups.add(new SearchConditionGroup("人员范围", true, conditionItems));
        addGroups.add(new SearchConditionGroup("人员范围排除", true, conditionItem));

        apidatas.put("condition", addGroups);
        return apidatas;
    }

    @Override
    public Map<String, Object> getSupplementaryForm(Map<String, Object> params) {


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

        //条件组
        List<SearchConditionGroup> addGroups = new ArrayList<>();
        List<SearchConditionItem> condition = new ArrayList<>();
        List<SearchConditionItem> conditionItems = new ArrayList<>();
        List<SearchConditionItem> conditionItem = new ArrayList<>();

        SearchConditionItem billMonthList = SalaryFormItemUtil.datePickerItem(user, 2, 16, true, 2, "补缴月份", "billMonth");
        billMonthList.setMultiple(true);
        billMonthList.setOtherParams(new HashMap<>());
        billMonthList.getOtherParams().put("type", "months");
        billMonthList.getOtherParams().put("format", "YYYY-MM");
        billMonthList.getOtherParams().put("showFormat", "YYYY-MM");
        billMonthList.setMultiple(true);
        billMonthList.setViewAttr(3);
        billMonthList.setRules("required");
        condition.add(billMonthList);

        SearchConditionItem billProjects = SalaryFormItemUtil.selectItem(user, buildBillProjectsOptions(), 2, 16, 6, true, "补缴项目", "projects");
        billProjects.setViewAttr(3);
        billProjects.setDetailtype(2);
        billProjects.setRules("required");
        condition.add(billProjects);

        SearchConditionItem includes = SalaryFormItemUtil.browserItem(user, 18, 6, 3, true, "对象", "required", "17", "includes");
        conditionItems.add(includes);
//        SearchConditionItem excludes = SalaryFormItemUtil.browserItem(user, 18, 6, 2, true, "选择人员", "required", "17", "excludes");
//        excludes.setViewAttr(2);
//        conditionItem.add(excludes);
        addGroups.add(new SearchConditionGroup("基础信息", true, condition));
        addGroups.add(new SearchConditionGroup("人员范围", true, conditionItems));
//        addGroups.add(new SearchConditionGroup("人员范围排除",true,conditionItem));

        apidatas.put("condition", addGroups);
        return apidatas;
    }

    @Override
    public PageInfo<InsuranceAccountViewListDTO> overView(InsuranceAccountDetailParam queryParam) {
//        PageInfo<InsuranceAccountViewListDTO> pageInfos = getSiAccountBiz(user).overView(queryParam);
        PageInfo<InsuranceAccountViewListDTO> pageInfos = siOverView(queryParam);
        return pageInfos;
    }

    @Override
    public List<Map<String, Object>> welfareData(String billMonth, List<Long> employeeIds, Long taxAgentId) {
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, taxAgentId);
        insuranceAccountBatchPO = encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        if (insuranceAccountBatchPO == null || Objects.equals(BillStatusEnum.NOT_ARCHIVED.getValue(), insuranceAccountBatchPO.getBillStatus())) {
            return Lists.newArrayList();
        }

        //20230707增加福利核算明细中的缴纳状态+合计的数据项
//        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().queryList(billMonth, taxAgentId, employeeIds);

        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = new ArrayList<>();
        List<List<Long>> empIdsPart = Lists.partition((List<Long>) employeeIds, 500);
        for (List<Long> part : empIdsPart) {
            insuranceAccountDetailPOS.addAll(
                    getInsuranceAccountDetailMapper().queryList(billMonth, taxAgentId, part));
        }

        //退差数据不参与薪资核算
        insuranceAccountDetailPOS = insuranceAccountDetailPOS.stream()
                .filter(f -> f.getPaymentStatus().equals(PaymentStatusEnum.COMMON.getValue())
                        || f.getPaymentStatus().equals(PaymentStatusEnum.REPAIR.getValue())
                        || f.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue()) )
                .collect(Collectors.toList());
        List<InsuranceAccountDetailPO> list = buildNewInsuranceDetailPOS(insuranceAccountDetailPOS);
        Map<String, InsuranceAccountDetailPO> siAcctResultWithEmpAndPayStatus = insuranceAccountDetailPOS.stream()
                .collect(Collectors.toMap(po -> po.getEmployeeId() + "_" + po.getPaymentStatus(), a -> a, (a, b) -> a));


        List<Map<String, Object>> result = new ArrayList<>();
        list.stream().forEach(item -> {
            Map<String, Object> record = new HashMap<>();
            record.put("employeeId", item.getEmployeeId());
            if (StringUtils.isNotEmpty(item.getSocialPerJson())) {
                Map<String, Object> socialJson = JSON.parseObject(item.getSocialPerJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialPer", v);
                });
            }
            if (StringUtils.isNotEmpty(item.getSocialComJson())) {
                Map<String, Object> socialJson = JSON.parseObject(item.getSocialComJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialCom", v);
                });
            }
            record.put("socialPerSum", item.getSocialPerSum());
            record.put("socialComSum", item.getSocialComSum());
            if (StringUtils.isNotEmpty(item.getFundPerJson())) {
                Map<String, Object> fundPerJson = JSON.parseObject(item.getFundPerJson(), new HashMap<String, Object>().getClass());
                fundPerJson.forEach((k, v) -> {
                    record.put(k + "fundPer", v);
                });
            }
            if (StringUtils.isNotEmpty(item.getFundComJson())) {
                Map<String, Object> fundPerJson = JSON.parseObject(item.getFundComJson(), new HashMap<String, Object>().getClass());
                fundPerJson.forEach((k, v) -> {
                    record.put(k + "fundCom", v);
                });
            }
            record.put("fundPerSum", item.getFundPerSum());
            record.put("fundComSum", item.getFundComSum());
            if (StringUtils.isNotEmpty(item.getOtherPerJson())) {
                Map<String, Object> fundPerJson = JSON.parseObject(item.getOtherPerJson(), new HashMap<String, Object>().getClass());
                fundPerJson.forEach((k, v) -> {
                    record.put(k + "otherPer", v);
                });
            }
            if (StringUtils.isNotEmpty(item.getOtherComJson())) {
                Map<String, Object> fundComJson = JSON.parseObject(item.getOtherComJson(), new HashMap<String, Object>().getClass());
                if (fundComJson != null) {

                }
                fundComJson.forEach((k, v) -> {
                    record.put(k + "otherCom", v);
                });
            }
            record.put("otherPerSum", item.getOtherPerSum());
            record.put("otherComSum", item.getOtherComSum());
            record.put("perSum", item.getPerSum());
            record.put("comSum", item.getComSum());

            //20230707增加福利核算明细中的缴纳状态+合计的数据项、缴纳状态+福利项的数据项
            InsuranceAccountDetailPO commonSiAcct = siAcctResultWithEmpAndPayStatus.get(item.getEmployeeId() + "_" + PaymentStatusEnum.COMMON.getValue());
            InsuranceAccountDetailPO repairSiAcct = siAcctResultWithEmpAndPayStatus.get(item.getEmployeeId() + "_" + PaymentStatusEnum.REPAIR.getValue());
            InsuranceAccountDetailPO balanceSiAcct = siAcctResultWithEmpAndPayStatus.get(item.getEmployeeId() + "_" + PaymentStatusEnum.BALANCE.getValue());
            //取正常缴纳的福利基数信息
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getSocialPaymentBaseString())) {
                Map<String, Object> socialBaseJson = JSON.parseObject(commonSiAcct.getSocialPaymentBaseString(), new HashMap<String, Object>().getClass());
                socialBaseJson.forEach((k, v) -> {
                    record.put(k + "socialBase", v);
                });
            }
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getFundPaymentBaseString())) {
                Map<String, Object> fundBaseJson = JSON.parseObject(commonSiAcct.getFundPaymentBaseString(), new HashMap<String, Object>().getClass());
                fundBaseJson.forEach((k, v) -> {
                    record.put(k + "fundBase", v);
                });
            }
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getOtherPaymentBaseString())) {
                Map<String, Object> otherBaseJson = JSON.parseObject(commonSiAcct.getOtherPaymentBaseString(), new HashMap<String, Object>().getClass());
                otherBaseJson.forEach((k, v) -> {
                    record.put(k + "otherBase", v);
                });
            }
            //社保-正常缴纳
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getSocialPerJson())) {
                Map<String, Object> socialJson = JSON.parseObject(commonSiAcct.getSocialPerJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialCommonPer", v);
                });
            }
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getSocialComJson())) {
                Map<String, Object> socialJson = JSON.parseObject(commonSiAcct.getSocialComJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialCommonCom", v);
                });
            }
            record.put("socialPerCommonSum", commonSiAcct != null ? commonSiAcct.getSocialPerSum() : new BigDecimal("0"));
            record.put("socialComCommonSum", commonSiAcct != null ? commonSiAcct.getSocialComSum() : new BigDecimal("0"));
            //社保-补缴
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getSocialPerJson())) {
                Map<String, Object> socialJson = JSON.parseObject(repairSiAcct.getSocialPerJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialRepairPer", v);
                });
            }
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getSocialComJson())) {
                Map<String, Object> socialJson = JSON.parseObject(repairSiAcct.getSocialComJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialRepairCom", v);
                });
            }
            record.put("socialPerRepairSum", repairSiAcct != null ? repairSiAcct.getSocialPerSum() : new BigDecimal("0"));
            record.put("socialComRepairSum", repairSiAcct != null ? repairSiAcct.getSocialComSum() : new BigDecimal("0"));
            //社保-补差
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getSocialPerJson())) {
                Map<String, Object> socialJson = JSON.parseObject(balanceSiAcct.getSocialPerJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialBalancePer", v);
                });
            }
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getSocialComJson())) {
                Map<String, Object> socialJson = JSON.parseObject(balanceSiAcct.getSocialComJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "socialBalanceCom", v);
                });
            }
            record.put("socialPerBalanceSum", balanceSiAcct != null ? balanceSiAcct.getSocialPerSum() : new BigDecimal("0"));
            record.put("socialComBalanceSum", balanceSiAcct != null ? balanceSiAcct.getSocialComSum() : new BigDecimal("0"));

            //公积金-正常缴纳
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getFundPerJson())) {
                Map<String, Object> socialJson = JSON.parseObject(commonSiAcct.getFundPerJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "fundCommonPer", v);
                });
            }
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getFundComJson())) {
                Map<String, Object> socialJson = JSON.parseObject(commonSiAcct.getFundComJson(), new HashMap<String, Object>().getClass());
                socialJson.forEach((k, v) -> {
                    record.put(k + "fundCommonCom", v);
                });
            }
            record.put("fundPerCommonSum", commonSiAcct != null ? commonSiAcct.getFundPerSum() : new BigDecimal("0"));
            record.put("fundComCommonSum", commonSiAcct != null ? commonSiAcct.getFundComSum() : new BigDecimal("0"));
            //公积金-补缴
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getFundPerJson())) {
                Map<String, Object> fundJson = JSON.parseObject(repairSiAcct.getFundPerJson(), new HashMap<String, Object>().getClass());
                fundJson.forEach((k, v) -> {
                    record.put(k + "fundRepairPer", v);
                });
            }
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getFundComJson())) {
                Map<String, Object> fundJson = JSON.parseObject(repairSiAcct.getFundComJson(), new HashMap<String, Object>().getClass());
                fundJson.forEach((k, v) -> {
                    record.put(k + "fundRepairCom", v);
                });
            }
            record.put("fundPerRepairSum", repairSiAcct != null ? repairSiAcct.getFundPerSum() : new BigDecimal("0"));
            record.put("fundComRepairSum", repairSiAcct != null ? repairSiAcct.getFundComSum() : new BigDecimal("0"));
            //公积金-补差
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getFundPerJson())) {
                Map<String, Object> fundJson = JSON.parseObject(balanceSiAcct.getFundPerJson(), new HashMap<String, Object>().getClass());
                fundJson.forEach((k, v) -> {
                    record.put(k + "fundBalancePer", v);
                });
            }
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getFundComJson())) {
                Map<String, Object> fundJson = JSON.parseObject(balanceSiAcct.getFundComJson(), new HashMap<String, Object>().getClass());
                fundJson.forEach((k, v) -> {
                    record.put(k + "fundBalanceCom", v);
                });
            }
            record.put("fundPerBalanceSum", balanceSiAcct != null ? balanceSiAcct.getFundPerSum() : new BigDecimal("0"));
            record.put("fundComBalanceSum", balanceSiAcct != null ? balanceSiAcct.getFundComSum() : new BigDecimal("0"));

            //其他福利-正常缴纳
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getOtherPerJson())) {
                Map<String, Object> otherJson = JSON.parseObject(commonSiAcct.getOtherPerJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherCommonPer", v);
                });
            }
            if (commonSiAcct != null && StringUtils.isNotEmpty(commonSiAcct.getOtherComJson())) {
                Map<String, Object> otherJson = JSON.parseObject(commonSiAcct.getOtherComJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherCommonCom", v);
                });
            }
            record.put("otherPerCommonSum", commonSiAcct != null ? commonSiAcct.getOtherPerSum() : new BigDecimal("0"));
            record.put("otherComCommonSum", commonSiAcct != null ? commonSiAcct.getOtherComSum() : new BigDecimal("0"));
            //其他福利-补缴
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getOtherPerJson())) {
                Map<String, Object> otherJson = JSON.parseObject(repairSiAcct.getOtherPerJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherRepairPer", v);
                });
            }
            if (repairSiAcct != null && StringUtils.isNotEmpty(repairSiAcct.getOtherComJson())) {
                Map<String, Object> otherJson = JSON.parseObject(repairSiAcct.getOtherComJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherRepairCom", v);
                });
            }
            record.put("otherPerRepairSum", repairSiAcct != null ? repairSiAcct.getOtherPerSum() : new BigDecimal("0"));
            record.put("otherComRepairSum", repairSiAcct != null ? repairSiAcct.getOtherComSum() : new BigDecimal("0"));
            //其他福利-补差
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getOtherPerJson())) {
                Map<String, Object> otherJson = JSON.parseObject(balanceSiAcct.getOtherPerJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherBalancePer", v);
                });
            }
            if (balanceSiAcct != null && StringUtils.isNotEmpty(balanceSiAcct.getOtherComJson())) {
                Map<String, Object> otherJson = JSON.parseObject(balanceSiAcct.getOtherComJson(), new HashMap<String, Object>().getClass());
                otherJson.forEach((k, v) -> {
                    record.put(k + "otherBalanceCom", v);
                });
            }
            record.put("otherPerBalanceSum", balanceSiAcct != null ? balanceSiAcct.getOtherPerSum() : new BigDecimal("0"));
            record.put("otherComBalanceSum", balanceSiAcct != null ? balanceSiAcct.getOtherComSum() : new BigDecimal("0"));

            record.put("perCommonSum", commonSiAcct != null ? commonSiAcct.getPerSum() : new BigDecimal("0"));
            record.put("comCommonSum", commonSiAcct != null ? commonSiAcct.getComSum() : new BigDecimal("0"));
            record.put("perRepairSum", repairSiAcct != null ? repairSiAcct.getPerSum() : new BigDecimal("0"));
            record.put("comRepairSum", repairSiAcct != null ? repairSiAcct.getComSum() : new BigDecimal("0"));
            record.put("perBalanceSum", balanceSiAcct != null ? balanceSiAcct.getPerSum() : new BigDecimal("0"));
            record.put("comBalanceSum", balanceSiAcct != null ? balanceSiAcct.getComSum() : new BigDecimal("0"));

            result.add(record);
        });
        return result;
    }

    @Override
    public Map<String, String> welfareColumns() {
        List<ICategoryPO> listAll = getICategoryMapper().listAll().stream().filter(f -> f.getIsUse().equals(IsUseEnum.START.getValue())).collect(Collectors.toList());
        List<ICategoryPO> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(listAll)) {
            list.addAll(listAll);
        }

        Map<String, String> result = new LinkedHashMap<>();

        Map<String, String> commonResult = new LinkedHashMap<>();
        Map<String, String> repairResult = new LinkedHashMap<>();
        Map<String, String> balanceResult = new LinkedHashMap<>();
        Map<String, String> baseResult = new LinkedHashMap<>();

        result.put(SalaryI18nUtil.getI18nLabel(100393, "个人合计"), "perSum");
        result.put(SalaryI18nUtil.getI18nLabel(100388, "社保个人合计"), "socialPerSum");
        result.put(SalaryI18nUtil.getI18nLabel(100390, "公积金个人合计"), "fundPerSum");
        result.put(SalaryI18nUtil.getI18nLabel(100392, "其他福利个人合计"), "otherPerSum");

        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "个人正常缴纳合计"), "perCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "社保个人正常缴纳合计"), "socialPerCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金个人正常缴纳合计"), "fundPerCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利个人正常缴纳合计"), "otherPerCommonSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "个人补缴合计"), "perRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "社保个人补缴合计"), "socialPerRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金个人补缴合计"), "fundPerRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利个人补缴合计"), "otherPerRepairSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "个人补差合计"), "perBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "社保个人补差合计"), "socialPerBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金个人补差合计"), "fundPerBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利个人补差合计"), "otherPerBalanceSum");

        Map<String, String> categoryIdNameMap = getSICategoryService(user).categoryIdNameMap();
        list.stream().forEach(item -> {
            if (Objects.equals(WelfareTypeEnum.SOCIAL_SECURITY.getValue(), item.getWelfareType())) {
                if (Objects.equals(DataTypeEnum.SYSTEM.getValue(), item.getDataType())) {
                    baseResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "申报基数"), item.getId() + "socialBase");
                }
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(87159, "个人"), item.getId() + "socialPer");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳个人"), item.getId() + "socialCommonPer");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴个人"), item.getId() + "socialRepairPer");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差个人"), item.getId() + "socialBalancePer");
            }
            if (Objects.equals(WelfareTypeEnum.ACCUMULATION_FUND.getValue(), item.getWelfareType())) {
                if (Objects.equals(DataTypeEnum.SYSTEM.getValue(), item.getDataType())) {
                    baseResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "申报基数"), item.getId() + "fundBase");
                }
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(87159, "个人"), item.getId() + "fundPer");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳个人"), item.getId() + "fundCommonPer");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴个人"), item.getId() + "fundRepairPer");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差个人"), item.getId() + "fundBalancePer");
            }
            if (Objects.equals(WelfareTypeEnum.OTHER.getValue(), item.getWelfareType())) {
                if (Objects.equals(DataTypeEnum.SYSTEM.getValue(), item.getDataType())) {
                    baseResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "申报基数"), item.getId() + "otherBase");
                }
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(87159, "个人"), item.getId() + "otherPer");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳个人"), item.getId() + "otherCommonPer");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴个人"), item.getId() + "otherRepairPer");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差个人"), item.getId() + "otherBalancePer");
            }

        });
        result.put(SalaryI18nUtil.getI18nLabel(100397, "单位合计"), "comSum");
        result.put(SalaryI18nUtil.getI18nLabel(100394, "社保单位合计"), "socialComSum");
        result.put(SalaryI18nUtil.getI18nLabel(100395, "公积金单位合计"), "fundComSum");
        result.put(SalaryI18nUtil.getI18nLabel(100396, "其他福利单位合计"), "otherComSum");

        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "单位正常缴纳合计"), "comCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "社保单位正常缴纳合计"), "socialComCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金单位正常缴纳合计"), "fundComCommonSum");
        commonResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利单位正常缴纳合计"), "otherComCommonSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "单位补缴合计"), "comRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "社保单位补缴合计"), "socialComRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金单位补缴合计"), "fundComRepairSum");
        repairResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利单位补缴合计"), "otherComRepairSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "单位补差合计"), "comBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "社保单位补差合计"), "socialComBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "公积金单位补差合计"), "fundComBalanceSum");
        balanceResult.put(SalaryI18nUtil.getI18nLabel(0, "其他福利单位补差合计"), "otherComBalanceSum");

        list.stream().forEach(item -> {
            if (Objects.equals(WelfareTypeEnum.SOCIAL_SECURITY.getValue(), item.getWelfareType())) {
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(100289, "单位"), item.getId() + "socialCom");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳单位"), item.getId() + "socialCommonCom");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴单位"), item.getId() + "socialRepairCom");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差单位"), item.getId() + "socialBalanceCom");
            }
            if (Objects.equals(WelfareTypeEnum.ACCUMULATION_FUND.getValue(), item.getWelfareType())) {
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(100289, "单位"), item.getId() + "fundCom");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳单位"), item.getId() + "fundCommonCom");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴单位"), item.getId() + "fundRepairCom");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差单位"), item.getId() + "fundBalanceCom");
            }
            if (Objects.equals(WelfareTypeEnum.OTHER.getValue(), item.getWelfareType())) {
                result.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(100289, "单位"), item.getId() + "otherCom");
                commonResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "正常缴纳单位"), item.getId() + "otherCommonCom");
                repairResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补缴单位"), item.getId() + "otherRepairCom");
                balanceResult.put(categoryIdNameMap.get(String.valueOf(item.getId())) + SalaryI18nUtil.getI18nLabel(0, "补差单位"), item.getId() + "otherBalanceCom");
            }
        });

        result.putAll(baseResult);
        result.putAll(commonResult);
        result.putAll(repairResult);
        result.putAll(balanceResult);
        return result;
    }


    public List<SearchConditionOption> buildBillProjectsOptions() {
        List<SearchConditionOption> options = new ArrayList<>();
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.ALL.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.ALL.getLabelId(), ProjectTypeEnum.ALL.getDefaultLabel())));
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.SOCIAL.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.SOCIAL.getLabelId(), ProjectTypeEnum.SOCIAL.getDefaultLabel())));
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.FUND.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.FUND.getLabelId(), ProjectTypeEnum.FUND.getDefaultLabel())));
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.OTHER.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.OTHER.getLabelId(), ProjectTypeEnum.OTHER.getDefaultLabel())));
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.ENDOWMENT_INSURANCE.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.ENDOWMENT_INSURANCE.getLabelId(), ProjectTypeEnum.ENDOWMENT_INSURANCE.getDefaultLabel())));
        options.add(new SearchConditionOption(String.valueOf(ProjectTypeEnum.MEDICAL_INSURANCE.getValue()),
                SalaryI18nUtil.getI18nLabel(ProjectTypeEnum.MEDICAL_INSURANCE.getLabelId(), ProjectTypeEnum.MEDICAL_INSURANCE.getDefaultLabel())));
        return options;
    }


    public List<InsuranceAccountDetailPO> queryList(String billMonth, Long taxAgentId, List<Long> employeeIds) {
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().queryList(billMonth, taxAgentId, employeeIds);
        //退差数据不参与薪资核算
        insuranceAccountDetailPOS = insuranceAccountDetailPOS.stream()
                .filter(f -> f.getPaymentStatus().equals(PaymentStatusEnum.COMMON.getValue())
                        || f.getPaymentStatus().equals(PaymentStatusEnum.REPAIR.getValue())
                        || f.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue()) )
                .collect(Collectors.toList());
        List<InsuranceAccountDetailPO> list = buildNewInsuranceDetailPOS(insuranceAccountDetailPOS);
//        InsuranceAccountDetailPOEncrypt.decryptInsuranceAccountDetailPOList(list);
        return list;
    }

    public List<InsuranceAccountDetailPO> buildNewInsuranceDetailPOS(List<InsuranceAccountDetailPO> list) {
        List<InsuranceAccountDetailPO> newList = new ArrayList<>();
        if (CollectionUtils.isEmpty(list)) {
            return newList;
        }
        Map<Long, List<InsuranceAccountDetailPO>> employeeMap = list.stream().filter(item -> item.getEmployeeId() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getEmployeeId));
        for (Map.Entry<Long, List<InsuranceAccountDetailPO>> entry : employeeMap.entrySet()) {
            Long k = entry.getKey();
            List<InsuranceAccountDetailPO> v = entry.getValue();
            InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
            insuranceAccountDetailPO.setEmployeeId(k);
            Map<String, String> socialPerMap = new HashMap<>();
            Map<String, String> fundPerMap = new HashMap<>();
            Map<String, String> otherPerMap = new HashMap<>();
            Map<String, String> socialComMap = new HashMap<>();
            Map<String, String> fundComMap = new HashMap<>();
            Map<String, String> otherComMap = new HashMap<>();
            BigDecimal socialPer = new BigDecimal("0");
            BigDecimal socialCom = new BigDecimal("0");
            BigDecimal fundPer = new BigDecimal("0");
            BigDecimal fundCom = new BigDecimal("0");
            BigDecimal otherPer = new BigDecimal("0");
            BigDecimal otherCom = new BigDecimal("0");
            BigDecimal perSum = new BigDecimal("0");
            BigDecimal comSum = new BigDecimal("0");
            for (InsuranceAccountDetailPO item : v) {
                encryptUtil.decrypt(item, InsuranceAccountDetailPO.class);
                insuranceAccountDetailPO.setId(item.getId());
                insuranceAccountDetailPO.setSocialPaymentBaseString(item.getSocialPaymentBaseString());
                insuranceAccountDetailPO.setFundPaymentBaseString(item.getFundPaymentBaseString());
                insuranceAccountDetailPO.setOtherPaymentBaseString(item.getOtherPaymentBaseString());
                BigDecimal socialPerSum = StringUtils.isBlank(item.getSocialPerSum()) ? new BigDecimal("0") : new BigDecimal(item.getSocialPerSum());
                BigDecimal socialComSum = StringUtils.isBlank(item.getSocialComSum()) ? new BigDecimal("0") : new BigDecimal(item.getSocialComSum());
                BigDecimal fundPerSum = StringUtils.isBlank(item.getFundPerSum()) ? new BigDecimal("0") : new BigDecimal(item.getFundPerSum());
                BigDecimal fundComSum = StringUtils.isBlank(item.getFundComSum()) ? new BigDecimal("0") : new BigDecimal(item.getFundComSum());
                BigDecimal otherPerSum = StringUtils.isBlank(item.getOtherPerSum()) ? new BigDecimal("0") : new BigDecimal(item.getOtherPerSum());
                BigDecimal otherComSum = StringUtils.isBlank(item.getOtherComSum()) ? new BigDecimal("0") : new BigDecimal(item.getOtherComSum());
                BigDecimal perSumItem = StringUtils.isBlank(item.getPerSum()) ? new BigDecimal("0") : new BigDecimal(item.getPerSum());
                BigDecimal comSumItem = StringUtils.isBlank(item.getComSum()) ? new BigDecimal("0") : new BigDecimal(item.getComSum());
                socialPer = socialPer.add(socialPerSum);
                socialCom = socialCom.add(socialComSum);
                fundPer = fundPer.add(fundPerSum);
                fundCom = fundCom.add(fundComSum);
                otherPer = otherPer.add(otherPerSum);
                otherCom = otherCom.add(otherComSum);
                perSum = perSum.add(perSumItem);
                comSum = comSum.add(comSumItem);
                if (StringUtils.isNotBlank(item.getSocialPerJson())) {
                    Map<String, String> socialJson = JSON.parseObject(item.getSocialPerJson(), new HashMap<String, String>().getClass());
                    if (socialJson != null) {
                        socialJson.forEach((insuranceId, num) -> {
                            if (socialPerMap.get(insuranceId) == null) {
                                socialPerMap.put(insuranceId, num);
                            } else {
                                String oldNum = socialPerMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                socialPerMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
                if (StringUtils.isNotBlank(item.getSocialComJson())) {
                    Map<String, String> socialJson = JSON.parseObject(item.getSocialComJson(), new HashMap<String, String>().getClass());
                    if (socialJson != null) {
                        socialJson.forEach((insuranceId, num) -> {
                            if (socialComMap.get(insuranceId) == null) {
                                socialComMap.put(insuranceId, num);
                            } else {
                                String oldNum = socialComMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                socialComMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
                if (StringUtils.isNotBlank(item.getFundPerJson())) {
                    Map<String, String> fundJson = JSON.parseObject(item.getFundPerJson(), new HashMap<String, String>().getClass());
                    if (fundJson != null) {
                        fundJson.forEach((insuranceId, num) -> {
                            if (fundPerMap.get(insuranceId) == null) {
                                fundPerMap.put(insuranceId, num);
                            } else {
                                String oldNum = fundPerMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                fundPerMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
                if (StringUtils.isNotBlank(item.getFundComJson())) {
                    Map<String, String> fundJson = JSON.parseObject(item.getFundComJson(), new HashMap<String, String>().getClass());
                    if (fundJson != null) {
                        fundJson.forEach((insuranceId, num) -> {
                            if (fundComMap.get(insuranceId) == null) {
                                fundComMap.put(insuranceId, num);
                            } else {
                                String oldNum = fundComMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                fundComMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
                if (StringUtils.isNotBlank(item.getOtherPerJson())) {
                    Map<String, String> otherJson = JSON.parseObject(item.getOtherPerJson(), new HashMap<String, String>().getClass());
                    if (otherJson != null) {
                        otherJson.forEach((insuranceId, num) -> {
                            if (otherPerMap.get(insuranceId) == null) {
                                otherPerMap.put(insuranceId, num);
                            } else {
                                String oldNum = otherPerMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                otherPerMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
                if (StringUtils.isNotBlank(item.getOtherComJson())) {
                    Map<String, String> otherJson = JSON.parseObject(item.getOtherComJson(), new HashMap<String, String>().getClass());
                    if (otherJson != null) {
                        otherJson.forEach((insuranceId, num) -> {
                            if (otherComMap.get(insuranceId) == null) {
                                otherComMap.put(insuranceId, num);
                            } else {
                                String oldNum = otherComMap.get(insuranceId);
                                BigDecimal insuanceNum = new BigDecimal("0");
                                BigDecimal oldDecimal = new BigDecimal(oldNum);
                                BigDecimal numDecimal = num == null ? new BigDecimal("0") : new BigDecimal(num);
                                insuanceNum = insuanceNum.add(numDecimal).add(oldDecimal);
                                otherComMap.put(insuranceId, insuanceNum.toPlainString());
                            }
                        });
                    }

                }
            }
            insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerMap));
            insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialComMap));
            insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerMap));
            insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComMap));
            insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerMap));
            insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComMap));
            insuranceAccountDetailPO.setSocialPerSum(socialPer.toPlainString());
            insuranceAccountDetailPO.setSocialComSum(socialCom.toPlainString());
            insuranceAccountDetailPO.setFundPerSum(fundPer.toPlainString());
            insuranceAccountDetailPO.setFundComSum(fundCom.toPlainString());
            insuranceAccountDetailPO.setOtherPerSum(otherPer.toPlainString());
            insuranceAccountDetailPO.setOtherComSum(otherCom.toPlainString());
            insuranceAccountDetailPO.setPerSum(perSum.toPlainString());
            insuranceAccountDetailPO.setComSum(comSum.toPlainString());
            newList.add(insuranceAccountDetailPO);
        }
        return newList;
    }


    @Override
    public List<InsuranceAccountInspectPO> allInspects(Collection<Long> ids, String billMonth) {
//        InsuranceAccountInspectMapper siAccountInspectMapper = MapperProxyFactory.getProxy(InsuranceAccountInspectMapper.class);
        List<InsuranceAccountInspectPO> list = getInsuranceAccountInspectMapper().getList(billMonth, InspectStatusEnum.IGNORE.getValue(), ids);
        if (CollectionUtils.isNotEmpty(list)) {
            return list;
        }
        return Collections.emptyList();
    }

    @Override
    public Collection<TaxAgentPO> getAdminTaxAgentList() {
        return getTaxAgentService(user).listAllTaxAgentsAsAdmin((long) user.getUID());
    }

    @Override
    public void socialSecurityBenefitsRecalculate(InsuranceAccountBatchPO param) {
        //fixme 重新核算的校验逻辑  1、先取台账对应扣缴义务人下的所有账套 2、取账套下所有核算记录 3、判断核算记录有没有使用对应月份的福利台账
//        int num = getSiAccountBiz(user).checkIfBusinessaccounting(param);
        int num = checkIfBusinessAccounting(param);
        //表示已经被核算过不能重新核算
        if (num > 0) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "已被薪酬核算给核算过，无法重新核算！"));
        }
        param.setBillStatus(0);
//        getSiAccountBiz(user).updateById(param);
        updateById(param);
        //记录操作日志
        InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getById(param.getId());
        encryptUtil.decrypt(targetPO, InsuranceAccountBatchPO.class);
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
        LoggerContext<InsuranceAccountBatchPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + targetPO.getId());
        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账-重新核算"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账-重新核算")
                + ": " + taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
        loggerContext.setNewValues(targetPO);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
    }

    /**
     * 导出“福利核算导入模板”
     */
    @Override
    public XSSFWorkbook exportImportTemplate(InsuranceAcctDetailImportTemplateParam param) {
        ValidUtil.doValidator(param);
        Long employeeId = (long) user.getUID();
        // 必须选择导入模板所需的薪资项目(福利项)
        if (CollectionUtils.isEmpty(param.getWelfareNames())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99019, "参数错误，请选择导入模板所需的福利项目核算项"));
        }

        // 模板表头(默认必带"个税扣缴义务人"、"姓名")
        List<Object> headerList = Lists.newArrayList(SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                "部门",
                SalaryI18nUtil.getI18nLabel(86186, "手机号"),
                SalaryI18nUtil.getI18nLabel(86317, "工号"),
                SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人"),
                "账单月份");
//        List<String> dataIndexList = Lists.newArrayList("username", "departmentName", "mobile", "workcode", "taxAgentName", "billMonth");
        List<String> dataIndexList = Lists.newArrayList("userName", "department", "mobile", "workcode", "socialPayOrg", "billMonth");
        // 查询福利核算项目
        List<String> welfareNames = (List<String>) param.getWelfareNames();
        headerList.addAll(welfareNames);
        //匹配welfareName对应的id
        List<InsuranceAcctDetailImportFieldDTO> welfareList = getSalaryFormulaWrapper(user).welfareList();
        Map<String, String> welfareNameMap = welfareList.stream().collect(Collectors.toMap(InsuranceAcctDetailImportFieldDTO::getSalaryItemName, InsuranceAcctDetailImportFieldDTO::getFieldId, (key1, key2) -> key2));
        welfareNames.forEach(f -> {
            if (StringUtils.isNotBlank(welfareNameMap.get(f))) {
                dataIndexList.add(welfareNameMap.get(f));
            }
        });
        // excel导出的数据
//        //查询当前已有的正常缴纳数据
//        List<Map<String, Object>> resultMapList = getNormalDataByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
//        // excel导出的数据
//        List<List<Object>> rows = Lists.newArrayListWithExpectedSize(resultMapList.size());
//        rows.add(headerList);
//        for (Map<String, Object> map : resultMapList) {
//            List<Object> row = Lists.newArrayListWithExpectedSize(headerList.size());
//            for (String dataIndex : dataIndexList) {
//                row.add(map.getOrDefault(dataIndex, StringUtils.EMPTY));
//            }
//            rows.add(row);
//        }

        InsuranceExportParam exportParam = new InsuranceExportParam();
        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        exportParam.setOrderRule(orderRule);
        exportParam.setBillMonth(param.getBillMonth());
        exportParam.setPaymentOrganization(param.getPaymentOrganization().toString());
        List<AccountExportPO> accountExportPOS = new ArrayList<>();
        accountExportPOS = getInsuranceExportMapper().exportAccount(PaymentStatusEnum.COMMON.getValue(), exportParam);
        //非系统人员核算明细
        List<AccountExportPO> extAccountExportPOS = getInsuranceExportMapper().exportExtAccount(PaymentStatusEnum.COMMON.getValue(), exportParam);
        accountExportPOS.addAll(extAccountExportPOS);
        encryptUtil.decryptList(accountExportPOS, AccountExportPO.class);
        SalaryI18nUtil.i18nList(accountExportPOS);
        // 数据组装
        List<Map<String, Object>> records = getSIExportService(user).buildCommonRecords(accountExportPOS);

        // excel导出的数据
        List<List<Object>> rows = Lists.newArrayListWithExpectedSize(records.size());
        rows.add(headerList);
        for (Map<String, Object> map : records) {
            List<Object> row = Lists.newArrayListWithExpectedSize(headerList.size());
            for (String dataIndex : dataIndexList) {
                row.add(map.getOrDefault(dataIndex, StringUtils.EMPTY));
            }
            rows.add(row);
        }

        String sheetName = "福利核算导入模板";
        return ExcelUtil.genWorkbookV2(rows, sheetName);
    }

    /**
     * 将福利核算模板导入的数据更新到数据库
     */
    @Override
    public Map<String, Object> importInsuranceAcctDetail(InsuranceAcctImportParam importParam) {
//        long currentEmployeeId = user.getUID();
//        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();

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

        //查询对于人员信息导入筛选的全局配置
        SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
        String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";
        //检验参数
        //excel文件id
        String imageId = Util.null2String(importParam.getImageId());

        if (StringUtils.isBlank(imageId)) {
            throw new SalaryRunTimeException("文件不存在");
        }
//        // 获取所有个税扣缴义务人
//        List<TaxAgentPO> taxAgents = getTaxAgentService(user).listAll();
//        Map<String, Long> taxAgentNameMap = SalaryEntityUtil.convert2Map(taxAgents, TaxAgentPO::getName, TaxAgentPO::getId);

        // 获取租户下所有的人员
        List<DataCollectionEmployee> salaryEmployees = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);

        // 失败的数量
        int failCount = 0;
        // 成功的数量
        int successCount = 0;
        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(importParam.getImageId()));

            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);

            // 错误提示信息
            List<Map> excelComments = Lists.newArrayList();
            // 存在错误的那行数据
            List<Map<String, Object>> errorDatas = Lists.newArrayList();
            // 表头
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);
            // 处理数值
            List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 1);
            if (CollectionUtils.isEmpty(headers)) {
                throw new SalaryRunTimeException("表头为空");
            }
            if (CollectionUtils.isEmpty(data)) {
                throw new SalaryRunTimeException("无数据");
            }
            //存储待更新的InsuranceAccountDetailPO数据
            List<InsuranceAccountDetailPO> updateInsuranceAccountDetailList = new ArrayList<>();
            //存储待新增的InsuranceAccountDetailPO数据
            List<InsuranceAccountDetailPO> insertInsuranceAccountDetailList = new ArrayList<>();
            //遍历excel表具体数据
            for (int i = 0; i < data.size(); i++) {

                String row = "第" + (i + 2) + "行";

                boolean isError = false;
                Map<String, Object> map = data.get(i);
                Long employeeId = 0L;
//                Long taxAgentId = 0L;

                List<InsuranceAccountDetailPO> list = new ArrayList<>();

                String billMonth = (String) map.getOrDefault("账单月份", "");
                String taxAgentName = (String) map.getOrDefault("个税扣缴义务人", "");
                String supplementaryMonth = (String) map.getOrDefault("补缴月份", "");
                Long paymentOrganization = 0L;
                List<TaxAgentPO> taxAgentPoList = getTaxAgentMapper().listByName(taxAgentName);

                if (taxAgentPoList.size() == 1) {
                    paymentOrganization = taxAgentPoList.get(0).getId();
                } else {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, SalaryI18nUtil.getI18nLabel(102840, "个税扣缴义务人错误，系统内不存在该个税扣缴义务人")));
                    excelComments.add(errorMessageMap);
                }

                if (billMonth.length() < 7 || !SalaryDateUtil.checkYearMonth(billMonth.substring(0, 7))) {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "账单月份输入有误，请参照“2022-09”这种格式进行检查"));
                    excelComments.add(errorMessageMap);
                }
                if (headers.contains("补缴月份") && (supplementaryMonth.length() < 7 || !SalaryDateUtil.checkYearMonth(supplementaryMonth.substring(0, 7)))) {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(0, "补缴月份输入有误，请参照“2022-09”这种格式进行检查"));
                    excelComments.add(errorMessageMap);
                }

                //遍历表头
                for (int j = 0; j < headers.size(); j++) {
                    String header = headers.get(j);
                    String dataKey = header;
                    if (dataKey == null) {
                        continue;
                    }
                    String dataValue = (String) map.getOrDefault(dataKey.toString(), "");
                    String deparmentName = (String) map.getOrDefault("部门", "");
                    String mobile = (String) map.getOrDefault("手机号", "");
                    String workcode = (String) map.getOrDefault("工号", "");
                    String idNo = (String) map.getOrDefault("证件号码", "");


                    if (StringUtils.equals(SalaryI18nUtil.getI18nLabel(85429, "姓名"), dataKey.toString())) {
                        //当人员信息导入筛选的全局配置为"0"时，姓名才是必填项
                        if (StringUtils.isEmpty(dataValue) && "0".equals(confValue)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(102838, "姓名不能为空"));
                            excelComments.add(errorMessageMap);

                        } else {
                            //筛选导入人员信息可以在人力资源池中匹配到的人员信息
                            List<DataCollectionEmployee> employeeSameIds = getSalaryEmployeeService(user).matchImportEmployee(confValue,salaryEmployees, dataValue, deparmentName, mobile, workcode,idNo, null);

                            if (CollectionUtils.isEmpty(employeeSameIds)) {
                                isError = true;
                                Map<String, String> errorMessageMap = Maps.newHashMap();
                                errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "姓名错误，系统内不存在该姓名"));
                                excelComments.add(errorMessageMap);

                            } else if (employeeSameIds.size() > 1) {
                                //存在离职和在职状态取在职状态
                                employeeSameIds = employeeSameIds.stream()
                                        .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
                                        .collect(Collectors.toList());
                                if (employeeSameIds.size() != 1) {
                                    isError = true;
                                    Map<String, String> errorMessageMap = Maps.newHashMap();
                                    errorMessageMap.put("message", row + "员工信息不存在或者存在多个员工");
                                    excelComments.add(errorMessageMap);
                                } else {
                                    employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0).getEmployeeId() : null;
                                }
                            } else {
                                employeeId = employeeSameIds.get(0).getEmployeeId();
                            }
                        }
                    }


                }

                if (!isError){
                    List<Long> employeeIds = new ArrayList<>();
                    employeeIds.add(employeeId);
                    //如果福利核算信息查询不到唯一匹配数据，不支持导入
                    //根据员工id、个税扣缴义务人id、账单月份查询
                    //根据表头字段来区分正常缴纳和补缴两类数据
                    if (!headers.contains("补缴月份")) {
                        list = getInsuranceAccountDetailMapper().queryNormalList(billMonth.substring(0, 7), paymentOrganization, employeeIds.get(0));
                    } else {
                        list = getInsuranceAccountDetailMapper().querySupplementList(billMonth.substring(0, 7), paymentOrganization, employeeIds.get(0), supplementaryMonth.substring(0, 7));
                    }

                    if (list.isEmpty()) {
                        if (headers.contains("补缴月份")) {
                            // 如果是补缴列表没有，则新增
                            if (supplementaryMonth.substring(0, 7).equals(billMonth.substring(0, 7))) {
                                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100481, "当前月走正常缴纳"));
                            }
                            //校验补缴人员是否存在福利档案基础信息，并且runStatus处于正在缴纳或者待减员
                            InsuranceArchivesBaseInfoPO insuranceBaseInfo = getInsuranceBaseInfoMapper().getOneByEmployeeIdAndPayOrg(paymentOrganization, employeeId);
                            if (insuranceBaseInfo == null || !(insuranceBaseInfo.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue()) || insuranceBaseInfo.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue())) ) {
                                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "补缴人员中存在未设置福利档案人员或相关人员不在福利在缴人员中，不可新建补缴信息！"));
                            }
                            List<Long> empIdsInPayMonthRange = listCanPayEmpIds(paymentOrganization, billMonth.substring(0, 7));
                            if (!empIdsInPayMonthRange.contains(employeeId)) {
                                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99920, "无核算人员"));
                            }
                            // 封装InsuranceAccountDetailPO
                            Date now = new Date();
                            InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
                            insuranceAccountDetailPO.setBillStatus(0);
                            insuranceAccountDetailPO.setEmployeeId(employeeId);
                            insuranceAccountDetailPO.setPaymentOrganization(paymentOrganization);
                            insuranceAccountDetailPO.setPaymentStatus(1);
                            insuranceAccountDetailPO.setResourceFrom(0);
                            insuranceAccountDetailPO.setSupplementaryProjects("0,1,2,3,4,5");
                            insuranceAccountDetailPO.setSocialPayOrg(paymentOrganization);
                            insuranceAccountDetailPO.setFundPayOrg(paymentOrganization);
                            insuranceAccountDetailPO.setOtherPayOrg(paymentOrganization);
                            insuranceAccountDetailPO.setCreator(Long.valueOf(user.getUID()));
                            insuranceAccountDetailPO.setCreateTime(now);
                            insuranceAccountDetailPO.setUpdateTime(now);
                            insuranceAccountDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
                            insuranceAccountDetailPO.setDeleteType(0);
                            InsuranceAccountDetailPO insertPO = handleInsuranceAccountDetail4AddSupplementary(insuranceAccountDetailPO, map);
                            if(!checkBalancePayInsurance(insertPO)) {
                                isError = true;
                                Map<String, String> errorMessageMap = Maps.newHashMap();
                                errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(0,  "导入数据中存在福利档案中未设置的福利项缴纳数值！"));
                                excelComments.add(errorMessageMap);
                            } else {
                                insertInsuranceAccountDetailList.add(insertPO);
                            }
                        } else {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579,  "本次福利核算不包含该人员"));
                            excelComments.add(errorMessageMap);
                        }
                    } else if (list.size() > 1) {
                        isError = true;
                        Map<String, String> errorMessageMap = Maps.newHashMap();
                        errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579,  "该人员本次核算出现多组数据，请删除数据库中多余核算项"));
                        excelComments.add(errorMessageMap);
                    } else {
                        //拼装待更新数据
                        encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
                        InsuranceAccountDetailPO updatePO = handleInsuranceAccountDetail(list.get(0), map);
                        //判断导入福利项是否符合福利方案设置缴纳项
                        if(!checkBalancePayInsurance(updatePO)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(0,  "导入数据中存在福利档案中未设置的福利项缴纳数值！"));
                            excelComments.add(errorMessageMap);
                        } else {
                            updateInsuranceAccountDetailList.add(updatePO);
                        }

                    }

                }

                if (isError) {
                    failCount++;
                    errorDatas.add(map);
                } else {
                    successCount++;
                }

            }
            //将待更新列表加密
            encryptUtil.encryptList(updateInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
            // 将待插入列表加密
            encryptUtil.encryptList(insertInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
            //更新
            for(InsuranceAccountDetailPO po : updateInsuranceAccountDetailList) {
//                getSiAccountBiz(user).updateByEmployeeIdAndBillMonth(po);
                updateByEmployeeIdAndBillMonth(po);
            }
            // 插入
            if (CollectionUtils.isNotEmpty(insertInsuranceAccountDetailList)) {
                getInsuranceAccountDetailMapper().batchSaveAccountDetails(insertInsuranceAccountDetailList);
            }

            //刷新hrsa_bill_batch中数据统计信息
            updateInsuranceAccountDetailList.addAll(insertInsuranceAccountDetailList);
            if (updateInsuranceAccountDetailList.size() > 0) {
                refreshBillBatch(updateInsuranceAccountDetailList.get(0).getPaymentOrganization(), updateInsuranceAccountDetailList.get(0).getBillMonth());
                //记录操作日志
                PaymentStatusEnum targetEnum = SalaryEnumUtil.enumMatchByValue(updateInsuranceAccountDetailList.get(0).getPaymentStatus(), PaymentStatusEnum.values(), PaymentStatusEnum.class);
                encryptUtil.decryptList(updateInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
                InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(updateInsuranceAccountDetailList.get(0).getBillMonth(), updateInsuranceAccountDetailList.get(0).getPaymentOrganization());
                TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
                LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
                loggerContext.setUser(user);
                loggerContext.setTargetId(String.valueOf(targetPO.getId()));
                loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                loggerContext.setOperateType(OperateTypeEnum.EXCEL_IMPORT.getValue());
                loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-导入")
                        + SalaryI18nUtil.getI18nLabel(targetEnum.getLabelId(), targetEnum.getDefaultLabel()));
                loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-导入"
                        + SalaryI18nUtil.getI18nLabel(targetEnum.getLabelId(), targetEnum.getDefaultLabel()))
                        + ":" + taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                updateInsuranceAccountDetailList.forEach(loggerContext::setNewValues);
                SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
            }

            apidatas.put("successCount", successCount);
            apidatas.put("errorCount", failCount);
            apidatas.put("errorData", excelComments);

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

    /**
     * 预览“福利核算导入”模板导入的数据
     */
    @Override
    public Map<String, Object> preview(InsuranceAcctImportParam param) {
        //1、参数校验
        String imageId = param.getImageId();
        if (StringUtils.isBlank(imageId)) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(100593, "文件id为空"));
        }

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

        InputStream fileInputStream = null;
        try {

            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(imageId));

            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);
        }
    }

    /**
     * 导出“福利核算-补缴导入”模板
     */
    @Override
    public XSSFWorkbook exportSupplyImportTemplate(InsuranceAcctDetailImportTemplateParam param) {
        ValidUtil.doValidator(param);

        // 必须选择导入模板所需的薪资项目(福利项)
        if (CollectionUtils.isEmpty(param.getWelfareNames())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99019, "参数错误，请选择导入模板所需的福利项目核算项"));
        }

        // 模板表头(默认必带"个税扣缴义务人"、"姓名")
        List<Object> headerList = Lists.newArrayList(SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                "部门",
                SalaryI18nUtil.getI18nLabel(86186, "手机号"),
                SalaryI18nUtil.getI18nLabel(86317, "工号"),
                SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人"),
                "账单月份",
                "补缴月份");
        List<String> dataIndexList = Lists.newArrayList("username", "departmentName", "mobile", "workcode", "taxAgentName", "billMonth", "supplementaryMonth");
        // 查询福利核算项目
        List<String> welfareNames = (List<String>) param.getWelfareNames();
        headerList.addAll(welfareNames);

        //查询当前已有的补缴数据
        List<Map<String, Object>> resultMapList = getSupplyDataByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
        // excel导出的数据
        List<List<Object>> rows = Lists.newArrayListWithExpectedSize(resultMapList.size());
        rows.add(headerList);
        for (Map<String, Object> map : resultMapList) {
            List<Object> row = Lists.newArrayListWithExpectedSize(headerList.size());
            for (String dataIndex : dataIndexList) {
                row.add(map.getOrDefault(dataIndex, StringUtils.EMPTY));
            }
            rows.add(row);
        }


        String sheetName = "福利核算-补缴导入模板";
        return ExcelUtil.genWorkbookV2(rows, sheetName);
    }

    /**
     * 获取福利台账中的补缴数据
     * @param billMonth 账单月份
     * @param paymentOrganization 个税扣缴义务人id
     * @return
     */
    private List<Map<String, Object>> getSupplyDataByBillMonth(String billMonth, Long paymentOrganization) {

        List<Map<String, Object>> resultList = new ArrayList<>();

        DataCollectionEmployee employee = new DataCollectionEmployee();

        TaxAgentPO taxAgentPO = taxAgentBiz.getById(paymentOrganization);

        List<InsuranceAccountDetailPO> supplyDataList = getInsuranceAccountDetailMapper().querySupplementListByBillMonth(billMonth, paymentOrganization);

        //过滤出福利档案基础信息表中runStatus为正在缴纳和待减员的人员
        List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
        List<Long> canAccountIds = baseInfoPOList.stream()
                .filter(f->f.getPaymentOrganization().equals(paymentOrganization)
                        && (f.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()) || f.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue())))
                .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
                .collect(Collectors.toList());
        supplyDataList = supplyDataList.stream().filter(f -> canAccountIds.contains(f.getEmployeeId())).collect(Collectors.toList());

        for(InsuranceAccountDetailPO po : supplyDataList) {
            Map<String, Object> resultMap = new HashMap<>();
            employee = getSalaryEmployeeService(user).getEmployeeById(po.getEmployeeId());
            resultMap.put("username", employee.getUsername());
            resultMap.put("departmentName", employee.getDepartmentName());
            resultMap.put("mobile", employee.getMobile());
            resultMap.put("workcode", employee.getWorkcode());
            resultMap.put("taxAgentName", taxAgentPO.getName());
            resultMap.put("billMonth", billMonth);
            resultMap.put("supplementaryMonth", po.getSupplementaryMonth());

            resultList.add(resultMap);
        }
        return resultList;
    }

    /**
     * 获取福利台账中的正常缴纳数据
     * @param billMonth 账单月份
     * @param paymentOrganization 个税扣缴义务人id
     * @return
     */
    private List<Map<String, Object>> getNormalDataByBillMonth(String billMonth, Long paymentOrganization) {

        List<Map<String, Object>> resultList = new ArrayList<>();

        DataCollectionEmployee employee = new DataCollectionEmployee();

        TaxAgentPO taxAgentPO = taxAgentBiz.getById(paymentOrganization);

        List<InsuranceAccountDetailPO> normalDataList = getInsuranceAccountDetailMapper().queryNormalListByBillMonth(billMonth, paymentOrganization);
        //过滤出福利档案基础信息表中runStatus为正在缴纳和待减员的人员
        List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
        List<Long> canAccountIds = baseInfoPOList.stream()
                .filter(f->f.getPaymentOrganization().equals(paymentOrganization)
                        && (f.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()) || f.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue())))
                .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
                .collect(Collectors.toList());
        normalDataList = normalDataList.stream().filter(f -> canAccountIds.contains(f.getEmployeeId())).collect(Collectors.toList());

        for(InsuranceAccountDetailPO po : normalDataList) {
            Map<String, Object> resultMap = new HashMap<>();
            employee = getSalaryEmployeeService(user).getEmployeeById(po.getEmployeeId());
            resultMap.put("username", employee.getUsername());
            resultMap.put("departmentName", employee.getDepartmentName());
            resultMap.put("mobile", employee.getMobile());
            resultMap.put("workcode", employee.getWorkcode());
            resultMap.put("taxAgentName", taxAgentPO.getName());
            resultMap.put("billMonth", billMonth);

            resultList.add(resultMap);
        }
        return resultList;
    }

    /**
     * 将更新的数据设置到老的insuranceAccountDetailPO对象中
     */
    private InsuranceAccountDetailPO handleInsuranceAccountDetail(InsuranceAccountDetailPO insuranceAccountDetailPO, Map<String, Object> baseMap) {

        //组装json数据,格式Map<String, Object>
        Map<String, String> socialPerMap = new HashMap<>();
        Map<String, String> fundPerMap = new HashMap<>();
        Map<String, String> otherPerMap = new HashMap<>();
        Map<String, String> socialComMap = new HashMap<>();
        Map<String, String> fundComMap = new HashMap<>();
        Map<String, String> otherComMap = new HashMap<>();

        //筛选出福利核算项
        Map<String, Object> toDealMap =
                baseMap.entrySet().stream()
                        .filter(map -> !"姓名".equals(map.getKey())
                                && !"部门".equals(map.getKey())
                                && !"手机号".equals(map.getKey())
                                && !"个税扣缴义务人".equals(map.getKey())
                                && !"账单月份".equals(map.getKey()))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        for(Map.Entry<String, Object> entry : toDealMap.entrySet()) {
            //判断元素是否属于福利类
            String keyName = entry.getKey();
            //获取元素名后缀，方便之后判断“个人”或“单位”
            String payScope = keyName.substring(keyName.length() - 2);
            //获取福利类型
            Integer welfareType;
//            List<ICategoryPO> categoryPOList = siCategoryBiz.listByName(entry.getKey().substring(0, keyName.length() - 2));
            List<ICategoryPO> categoryPOList = getSICategoryService(user).listByName(entry.getKey().substring(0, keyName.length() - 2));
            if (categoryPOList.size() == 1) {
                ICategoryPO iCategoryPO = categoryPOList.get(0);
                welfareType = iCategoryPO.getWelfareType();

                if ("个人".equals(payScope)) {
                    switch (welfareType) {
                        case 1:
                            socialPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 2:
                            fundPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 3:
                            otherPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        default:
                            throw new SalaryRunTimeException("福利类型不存在");
                    }
                } else if ("单位".equals(payScope)) {
                    switch (welfareType) {
                        case 1:
                            socialComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 2:
                            fundComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 3:
                            otherComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        default:
                            throw new SalaryRunTimeException("福利类型不存在");
                    }
                }
            }

        }

        //组装新的insuranceAccountDetailPO对象数据
        if (!socialPerMap.isEmpty()) {
            //对比新旧json中数据，并输出最终json
            checkJsonMap(socialPerMap, insuranceAccountDetailPO.getSocialPerJson());
            insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerMap));
        }

        if (!socialComMap.isEmpty()) {
            checkJsonMap(socialComMap, insuranceAccountDetailPO.getSocialComJson());
            insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialComMap));
        }

        if (!fundPerMap.isEmpty()) {
            checkJsonMap(fundPerMap, insuranceAccountDetailPO.getFundPerJson());
            insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerMap));
        }

        if (!fundComMap.isEmpty()) {
            checkJsonMap(fundComMap, insuranceAccountDetailPO.getFundComJson());
            insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComMap));
        }

        if (!otherPerMap.isEmpty()) {
            checkJsonMap(otherPerMap, insuranceAccountDetailPO.getOtherPerJson());
            insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerMap));
        }

        if (!otherComMap.isEmpty()) {
            checkJsonMap(otherComMap, insuranceAccountDetailPO.getOtherComJson());
            insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComMap));
        }


        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保个人合计", "").toString())) {
            insuranceAccountDetailPO.setSocialPerSum(baseMap.get("社保个人合计").toString());
        } else if (!socialPerMap.isEmpty()) {
            insuranceAccountDetailPO.setSocialPerSum(sumOfMapValue(socialPerMap));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金个人合计", "").toString())) {
            insuranceAccountDetailPO.setFundPerSum(baseMap.get("公积金个人合计").toString());
        } else if (!fundPerMap.isEmpty()) {
            insuranceAccountDetailPO.setFundPerSum(sumOfMapValue(fundPerMap));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利个人合计", "").toString())) {
            insuranceAccountDetailPO.setOtherPerSum(baseMap.get("其他福利个人合计").toString());
        } else if (!otherPerMap.isEmpty()) {
            insuranceAccountDetailPO.setOtherPerSum(sumOfMapValue(otherPerMap));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("个人合计", "").toString())) {
            insuranceAccountDetailPO.setPerSum(baseMap.get("个人合计").toString());
        } else {
            insuranceAccountDetailPO.setPerSum(new BigDecimal(insuranceAccountDetailPO.getSocialPerSum() == null ? "0" : insuranceAccountDetailPO.getSocialPerSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getFundPerSum() == null ? "0" : insuranceAccountDetailPO.getFundPerSum()))
                    .add(new BigDecimal(insuranceAccountDetailPO.getOtherPerSum() == null ? "0" : insuranceAccountDetailPO.getOtherPerSum())).toString());
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保单位合计", "").toString())) {
            insuranceAccountDetailPO.setSocialComSum(baseMap.get("社保单位合计").toString());
        } else if (!socialComMap.isEmpty()) {
            insuranceAccountDetailPO.setSocialComSum(sumOfMapValue(socialComMap));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金单位合计", "").toString())) {
            insuranceAccountDetailPO.setFundComSum(baseMap.get("公积金单位合计").toString());
        } else if (!fundComMap.isEmpty()) {
            insuranceAccountDetailPO.setFundComSum(sumOfMapValue(fundComMap));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利单位合计", "").toString())) {
            insuranceAccountDetailPO.setOtherComSum(baseMap.get("其他福利单位合计").toString());
        } else if (!otherComMap.isEmpty()) {
            insuranceAccountDetailPO.setOtherComSum(sumOfMapValue(otherComMap));
        }


        if (!StringUtils.isEmpty(baseMap.getOrDefault("单位合计", "").toString())) {
            insuranceAccountDetailPO.setComSum(baseMap.get("单位合计").toString());
        } else {
            insuranceAccountDetailPO.setComSum(new BigDecimal(insuranceAccountDetailPO.getSocialComSum() == null ? "0" : insuranceAccountDetailPO.getSocialComSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getFundComSum() == null ? "0" : insuranceAccountDetailPO.getFundComSum()))
                    .add(new BigDecimal(insuranceAccountDetailPO.getOtherComSum() == null ? "0" : insuranceAccountDetailPO.getOtherComSum())).toString());
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("账单月份", "").toString())) {
            insuranceAccountDetailPO.setBillMonth(baseMap.get("账单月份").toString().substring(0, 7));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保合计", "").toString())) {
            insuranceAccountDetailPO.setSocialSum(baseMap.get("社保合计").toString());
        } else {
            insuranceAccountDetailPO.setSocialSum(new BigDecimal(insuranceAccountDetailPO.getSocialComSum() == null ? "0" : insuranceAccountDetailPO.getSocialComSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getSocialPerSum() == null ? "0" : insuranceAccountDetailPO.getSocialPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金合计", "").toString())) {
            insuranceAccountDetailPO.setFundSum(baseMap.get("公积金合计").toString());
        } else {
            insuranceAccountDetailPO.setFundSum(new BigDecimal(insuranceAccountDetailPO.getFundComSum() == null ? "0" : insuranceAccountDetailPO.getFundComSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getFundPerSum() == null ? "0" : insuranceAccountDetailPO.getFundPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利合计", "").toString())) {
            insuranceAccountDetailPO.setOtherSum(baseMap.get("其他福利合计").toString());
        } else {
            insuranceAccountDetailPO.setOtherSum(new BigDecimal(insuranceAccountDetailPO.getOtherComSum() == null ? "0" : insuranceAccountDetailPO.getOtherComSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getOtherPerSum() == null ? "0" : insuranceAccountDetailPO.getOtherPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("合计", "").toString())) {
            insuranceAccountDetailPO.setTotal(baseMap.get("合计").toString());
        } else {
            insuranceAccountDetailPO.setTotal(new BigDecimal(insuranceAccountDetailPO.getPerSum() == null ? "0" : insuranceAccountDetailPO.getPerSum())
                    .add(new BigDecimal(insuranceAccountDetailPO.getComSum() == null ? "0" : insuranceAccountDetailPO.getComSum()))
                    .toString());
        }

        //如果导入的时补缴数据，还会包含补缴月份
        if (!StringUtils.isEmpty(baseMap.getOrDefault("补缴月份", "").toString())) {
            insuranceAccountDetailPO.setSupplementaryMonth(baseMap.get("补缴月份").toString().substring(0, 7));
        }

        insuranceAccountDetailPO.setUpdateTime(new Date());

        return insuranceAccountDetailPO;
    }

    private InsuranceAccountDetailPO handleInsuranceAccountDetail4AddSupplementary(InsuranceAccountDetailPO po, Map<String, Object> baseMap) {

        //组装json数据,格式Map<String, Object>
        Map<String, String> socialPerMap = new HashMap<>();
        Map<String, String> fundPerMap = new HashMap<>();
        Map<String, String> otherPerMap = new HashMap<>();
        Map<String, String> socialComMap = new HashMap<>();
        Map<String, String> fundComMap = new HashMap<>();
        Map<String, String> otherComMap = new HashMap<>();

        //筛选出福利核算项
        Map<String, Object> toDealMap =
                baseMap.entrySet().stream()
                        .filter(map -> !"姓名".equals(map.getKey())
                                && !"部门".equals(map.getKey())
                                && !"手机号".equals(map.getKey())
                                && !"个税扣缴义务人".equals(map.getKey())
                                && !"账单月份".equals(map.getKey()))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        for(Map.Entry<String, Object> entry : toDealMap.entrySet()) {
            //判断元素是否属于福利类
            String keyName = entry.getKey();
            //获取元素名后缀，方便之后判断“个人”或“单位”
            String payScope = keyName.substring(keyName.length() - 2);
            //获取福利类型
            Integer welfareType;
//            List<ICategoryPO> categoryPOList = siCategoryBiz.listByName(entry.getKey().substring(0, keyName.length() - 2));
            List<ICategoryPO> categoryPOList = getSICategoryService(user).listByName(entry.getKey().substring(0, keyName.length() - 2));
            if (categoryPOList.size() == 1) {
                ICategoryPO iCategoryPO = categoryPOList.get(0);
                welfareType = iCategoryPO.getWelfareType();

                if ("个人".equals(payScope)) {
                    switch (welfareType) {
                        case 1:
                            socialPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 2:
                            fundPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 3:
                            otherPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        default:
                            throw new SalaryRunTimeException("福利类型不存在");
                    }
                } else if ("单位".equals(payScope)) {
                    switch (welfareType) {
                        case 1:
                            socialComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 2:
                            fundComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        case 3:
                            otherComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
                            break;
                        default:
                            throw new SalaryRunTimeException("福利类型不存在");
                    }
                }
            }

        }

        //组装新的insuranceAccountDetailPO对象数据
        if (!socialPerMap.isEmpty()) {
            //对比新旧json中数据，并输出最终json
            checkJsonMap(socialPerMap, null);
            po.setSocialPerJson(JSON.toJSONString(socialPerMap));
        }

        if (!socialComMap.isEmpty()) {
            checkJsonMap(socialComMap, null);
            po.setSocialComJson(JSON.toJSONString(socialComMap));
        }

        if (!fundPerMap.isEmpty()) {
            checkJsonMap(fundPerMap, null);
            po.setFundPerJson(JSON.toJSONString(fundPerMap));
        }

        if (!fundComMap.isEmpty()) {
            checkJsonMap(fundComMap, null);
            po.setFundComJson(JSON.toJSONString(fundComMap));
        }

        if (!otherPerMap.isEmpty()) {
            checkJsonMap(otherPerMap, null);
            po.setOtherPerJson(JSON.toJSONString(otherPerMap));
        }

        if (!otherComMap.isEmpty()) {
            checkJsonMap(otherComMap, null);
            po.setOtherComJson(JSON.toJSONString(otherComMap));
        }


        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保个人合计", "").toString())) {
            po.setSocialPerSum(baseMap.get("社保个人合计").toString());
        } else if (!socialPerMap.isEmpty()) {
            po.setSocialPerSum(sumOfMapValue(socialPerMap));
        } else {
            po.setSocialPerSum("0");
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金个人合计", "").toString())) {
            po.setFundPerSum(baseMap.get("公积金个人合计").toString());
        } else if (!fundPerMap.isEmpty()) {
            po.setFundPerSum(sumOfMapValue(fundPerMap));
        } else {
            po.setFundPerSum("0");
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利个人合计", "").toString())) {
            po.setOtherPerSum(baseMap.get("其他福利个人合计").toString());
        } else if (!otherPerMap.isEmpty()) {
            po.setOtherPerSum(sumOfMapValue(otherPerMap));
        } else {
            po.setOtherPerSum("0");
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("个人合计", "").toString())) {
            po.setPerSum(baseMap.get("个人合计").toString());
        } else {
            po.setPerSum(new BigDecimal(po.getSocialPerSum() == null ? "0" : po.getSocialPerSum())
                    .add(new BigDecimal(po.getFundPerSum() == null ? "0" : po.getFundPerSum()))
                    .add(new BigDecimal(po.getOtherPerSum() == null ? "0" : po.getOtherPerSum())).toString());
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保单位合计", "").toString())) {
            po.setSocialComSum(baseMap.get("社保单位合计").toString());
        } else if (!socialComMap.isEmpty()) {
            po.setSocialComSum(sumOfMapValue(socialComMap));
        } else {
            po.setSocialComSum("0");
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金单位合计", "").toString())) {
            po.setFundComSum(baseMap.get("公积金单位合计").toString());
        } else if (!fundComMap.isEmpty()) {
            po.setFundComSum(sumOfMapValue(fundComMap));
        } else {
            po.setFundComSum("0");
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利单位合计", "").toString())) {
            po.setOtherComSum(baseMap.get("其他福利单位合计").toString());
        } else if (!otherComMap.isEmpty()) {
            po.setOtherComSum(sumOfMapValue(otherComMap));
        } else {
            po.setOtherComSum("0");
        }


        if (!StringUtils.isEmpty(baseMap.getOrDefault("单位合计", "").toString())) {
            po.setComSum(baseMap.get("单位合计").toString());
        } else {
            po.setComSum(new BigDecimal(po.getSocialComSum() == null ? "0" : po.getSocialComSum())
                    .add(new BigDecimal(po.getFundComSum() == null ? "0" : po.getFundComSum()))
                    .add(new BigDecimal(po.getOtherComSum() == null ? "0" : po.getOtherComSum())).toString());
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("账单月份", "").toString())) {
            po.setBillMonth(baseMap.get("账单月份").toString().substring(0, 7));
        }

        if (!StringUtils.isEmpty(baseMap.getOrDefault("社保合计", "").toString())) {
            po.setSocialSum(baseMap.get("社保合计").toString());
        } else {
            po.setSocialSum(new BigDecimal(po.getSocialComSum() == null ? "0" : po.getSocialComSum())
                    .add(new BigDecimal(po.getSocialPerSum() == null ? "0" : po.getSocialPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("公积金合计", "").toString())) {
            po.setFundSum(baseMap.get("公积金合计").toString());
        } else {
            po.setFundSum(new BigDecimal(po.getFundComSum() == null ? "0" : po.getFundComSum())
                    .add(new BigDecimal(po.getFundPerSum() == null ? "0" : po.getFundPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("其他福利合计", "").toString())) {
            po.setOtherSum(baseMap.get("其他福利合计").toString());
        } else {
            po.setOtherSum(new BigDecimal(po.getOtherComSum() == null ? "0" : po.getOtherComSum())
                    .add(new BigDecimal(po.getOtherPerSum() == null ? "0" : po.getOtherPerSum()))
                    .toString());
        }
        if (!StringUtils.isEmpty(baseMap.getOrDefault("合计", "").toString())) {
            po.setTotal(baseMap.get("合计").toString());
        } else {
            po.setTotal(new BigDecimal(po.getPerSum() == null ? "0" : po.getPerSum())
                    .add(new BigDecimal(po.getComSum() == null ? "0" : po.getComSum()))
                    .toString());
        }

        //如果导入的时补缴数据，还会包含补缴月份
        if (!StringUtils.isEmpty(baseMap.getOrDefault("补缴月份", "").toString())) {
            po.setSupplementaryMonth(baseMap.get("补缴月份").toString().substring(0, 7));
        }

        po.setUpdateTime(new Date());

        return po;
    }

    /**
     * map中value值求和
     */
    public String sumOfMapValue(Map<String, String> welfarePay){
        BigDecimal sum = new BigDecimal("0");
        for (String value : welfarePay.values()) {
            sum = sum.add(new BigDecimal(value));
        }
        return sum.toString();
    }

    /**
     * 对比新旧两份数据，并更新数据
     */
    private Map<String, String> checkJsonMap(Map<String, String> newMap, String oldJson) {
        Map<String, String> oldMap = JSON.parseObject(oldJson, HashMap.class);

        Map<String, String> toDelMap = new HashMap<>();
        //校验newMap中的value值是否为整数或者小数
        for(Map.Entry<String, String> newEntry : newMap.entrySet()) {
            String newValue = newEntry.getValue();
            int l = newValue.length();

            if (newValue.length() > 0 && !isNumeric(newValue)) {
                throw new SalaryRunTimeException("请检查导入Excel中个人或单位对应的福利项数值是否为整数或小数！");
            }

            if ("".equals(newEntry.getValue())) {
                toDelMap.put(newEntry.getKey(), newEntry.getValue());
            }
        }
        if (toDelMap.size() > 0) {
            for (Map.Entry<String, String> delEntry : toDelMap.entrySet()) {
                newMap.remove(delEntry.getKey());
            }
        }


        if (oldMap == null) {
            return newMap;
        }
        //保留oldMap无变动数据，更新newMap已变动数据
        for (Map.Entry<String, String> oldEntry : oldMap.entrySet()) {
            if (!newMap.containsKey(oldEntry.getKey())) {
                newMap.put(oldEntry.getKey(), oldEntry.getValue());
            } else if (newMap.containsKey(oldEntry.getKey()) && "".equals(newMap.get(oldEntry.getKey()))) {
                newMap.put(oldEntry.getKey(), oldEntry.getValue());
            }
        }

        return newMap;
    }

    /**
     * 判断字符串是否为整数或者小数或者负数
     */
    public static boolean isNumeric(String str){

//        Pattern pattern = Pattern.compile("[0-9]*\\.?[0-9]+");
        Pattern pattern = Pattern.compile("^-?\\d+(\\.\\d+)?$");
        Matcher isNum = pattern.matcher(str);
        if (!isNum.matches()) {
            return false;
        }
        return true;


    }

    /**
     * 校验福利核算的账单月份输入格式是否正确
     */
    public boolean checkBillMonth(String billMonth) {

        //校验内容：billMonth的长度是否为7、年月连接符是否为“-”
        String connector;
        if(billMonth.length() == 7){
            connector = billMonth.substring(4,5);
            return "-".equals(connector);
        } else {
            return false;
        }
    }

    /**
     * 导出“福利核算-线下对比导入模板”
     */
    @Override
    public XSSFWorkbook exportComparisonWelfareTemplate(InsuranceAccountDetailParam param) {
        Map<String, List<Object>> welColumnMap = createWelColumnMap(param);

        List<Object> headerList = Lists.newArrayList(SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                SalaryI18nUtil.getI18nLabel(86185, "部门"),
                SalaryI18nUtil.getI18nLabel(86186, "手机号"),
                SalaryI18nUtil.getI18nLabel(86317, "工号"),
                SalaryI18nUtil.getI18nLabel(86187, "员工状态"),
                SalaryI18nUtil.getI18nLabel(100377, "数据来源"),
                SalaryI18nUtil.getI18nLabel(91325, "个税扣缴义务人"));
        headerList.add(SalaryI18nUtil.getI18nLabel(91324, "社保账号"));
        headerList.add(SalaryI18nUtil.getI18nLabel(91323, "社保方案名称"));
        //组装社保基数
        if (welColumnMap.get("socialBase") != null) {
            headerList.addAll(welColumnMap.get("socialBase"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(91486, "公积金账号"));
        headerList.add(SalaryI18nUtil.getI18nLabel(91485, "公积金方案名称"));
        //组装公积金基数
        if (welColumnMap.get("fundBase") != null) {
            headerList.addAll(welColumnMap.get("fundBase"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(91487, "补充公积金账号"));
        headerList.add(SalaryI18nUtil.getI18nLabel(91496, "其他福利方案名称"));
        //组装其他福利基数
        if (welColumnMap.get("otherBase") != null) {
            headerList.addAll(welColumnMap.get("otherBase"));
        }
        //社保个人（生育保险个人、工伤保险个人、失业保险个人、养老保险个人、医疗保险个人）
        if (welColumnMap.get("socialPer") != null) {
            headerList.addAll(welColumnMap.get("socialPer"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100388, "社保个人合计"));
        //住房公积金个人、补充住房公积金个人
        if (welColumnMap.get("fundPer") != null) {
            headerList.addAll(welColumnMap.get("fundPer"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100390, "公积金个人合计"));
        //其他个人（比如企业年金个人）
        if (welColumnMap.get("otherPer") != null) {
            headerList.addAll(welColumnMap.get("otherPer"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100392, "其他福利个人合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(100393, "个人合计"));
        //社保单位（生育保险单位、工伤保险单位、失业保险单位、养老保险单位、医疗保险单位）
        if (welColumnMap.get("socialCom") != null) {
            headerList.addAll(welColumnMap.get("socialCom"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100394, "社保单位合计"));
        //住房公积金单位、补充住房公积金单位
        if (welColumnMap.get("fundCom") != null) {
            headerList.addAll(welColumnMap.get("fundCom"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100395, "公积金单位合计"));
        //其他单位（比如企业年金单位）
        if (welColumnMap.get("otherCom") != null) {
            headerList.addAll(welColumnMap.get("otherCom"));
        }
        headerList.add(SalaryI18nUtil.getI18nLabel(100396, "其他福利单位合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(100397, "单位合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(100398, "社保合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(100399, "公积金合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(100400, "其他福利合计"));
        headerList.add(SalaryI18nUtil.getI18nLabel(93278, "合计"));

        List<List<Object>> rows = new ArrayList<>();
        rows.add(headerList);
        String sheetName = "福利核算-线下对比导入模板";

        return ExcelUtilPlus.genWorkbookV2(rows, sheetName);
    }

    public Map<String, List<Object>> createWelColumnMap(InsuranceAccountDetailParam param) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();
        //查询线上福利核算记录
        InsuranceExportParam insuranceExportParam = new InsuranceExportParam();
        insuranceExportParam.setBillMonth(param.getBillMonth());
        insuranceExportParam.setPaymentOrganization(param.getPaymentOrganization());
        List<AccountExportPO> accountExportPOS = getInsuranceExportMapper().exportAccount(param.getPaymentStatus(), insuranceExportParam);

        //整理线上核算记录相关的福利方案，并以此整理需要对比的福利项类别数据
        Set<Long> welfareSchemeIds = new HashSet<>();
        accountExportPOS.forEach(f -> {
            welfareSchemeIds.add(f.getSocialSchemeId());
            welfareSchemeIds.add(f.getFundSchemeId());
            welfareSchemeIds.add(f.getOtherSchemeId());
        });
        List<InsuranceSchemeDetailPO> insuranceSchemeDetailPos = getInsuranceSchemeDetailMapper().listAll();
        List<Long> insuranceBaseIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        List<Long> insurancePerPayIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1 && f.getPaymentScope() == 2)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        List<Long> insuranceComPayIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1 && f.getPaymentScope() == 1)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        Set<Long> insuranceBaseSet = new HashSet<>(insuranceBaseIds);
        Set<Long> insurancePerPaySet = new HashSet<>(insurancePerPayIds);
        Set<Long> insuranceComPaySet = new HashSet<>(insuranceComPayIds);

        List<ICategoryPO> listAll = getICategoryMapper().listAll();
        List<ICategoryPO> socialWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());

        List<ICategoryPO> socialWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());

        List<ICategoryPO> socialWelComList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelComList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelComList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());

        //组装社保基数
        List<Object> socialBaseColumns = new ArrayList<>();
        List<Object> socialPerBaseColumns = new ArrayList<>();
        List<Object> socialComBaseColumns = Lists.newArrayList();
        if (welBaseDiffSign) {
            for (ICategoryPO po : socialWelfareList) {
                socialPerBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"个人"));
                socialComBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"单位"));
            }
            socialBaseColumns.addAll(socialPerBaseColumns);
            socialBaseColumns.addAll(socialComBaseColumns);
        } else {
            for (ICategoryPO po : socialWelfareList) {
                socialBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数"));
            }
        }

        //组装公积金基数
        List<Object> fundBaseColumns = new ArrayList<>();
        List<Object> fundPerBaseColumns = Lists.newArrayList();
        List<Object> fundComBaseColumns = Lists.newArrayList();
        if (welBaseDiffSign) {
            for (ICategoryPO po : fundWelfareList) {
                fundPerBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"个人"));
                fundComBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"单位"));
            }
            fundBaseColumns.addAll(fundPerBaseColumns);
            fundBaseColumns.addAll(fundComBaseColumns);
        } else {
            for (ICategoryPO po : fundWelfareList) {
                fundBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数"));
            }
        }

        //组装其他福利基数
        List<Object> otherBaseColumns = new ArrayList<>();
        List<Object> otherPerBaseColumns = new ArrayList<>();
        List<Object> otherComBaseColumns = Lists.newArrayList();
        if (welBaseDiffSign) {
            for (ICategoryPO po : otherWelfareList) {
                otherPerBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"个人"));
                otherComBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数") + SalaryI18nUtil.getI18nLabel(0,"单位"));
            }
            otherBaseColumns.addAll(otherPerBaseColumns);
            otherBaseColumns.addAll(otherComBaseColumns);
        } else {
            for (ICategoryPO po : otherWelfareList) {
                otherBaseColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0, "申报基数"));
            }
        }

        //社保个人（生育保险个人、工伤保险个人、失业保险个人、养老保险个人、医疗保险个人）
        List<Object> socialPerColumns = new ArrayList<>();
        for (ICategoryPO po : socialWelPerList) {
            socialPerColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"个人"));
        }
        //住房公积金个人、补充住房公积金个人
        List<Object> fundPerColumns = new ArrayList<>();
        for (ICategoryPO po : fundWelPerList) {
            fundPerColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"个人"));
        }
        //其他个人（比如企业年金个人）
        List<Object> otherPerColumns = new ArrayList<>();
        for (ICategoryPO po : otherWelPerList) {
            otherPerColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"个人"));
        }
        //社保单位（生育保险单位、工伤保险单位、失业保险单位、养老保险单位、医疗保险单位）
        List<Object> socialComColumns = new ArrayList<>();
        for (ICategoryPO po : socialWelComList) {
            socialComColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"单位"));
        }
        //住房公积金单位、补充住房公积金单位
        List<Object> fundComColumns = new ArrayList<>();
        for (ICategoryPO po : fundWelComList) {
            fundComColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"单位"));
        }

        //其他单位（比如企业年金单位）
        List<Object> otherComColumns = new ArrayList<>();
        for (ICategoryPO po : otherWelComList) {
            otherComColumns.add(po.getInsuranceName() + SalaryI18nUtil.getI18nLabel(0,"单位"));
        }

        Map<String, List<Object>> welColumnMap = new HashMap<>();
        welColumnMap.put("socialPerBase", socialPerBaseColumns);
        welColumnMap.put("fundPerBase", fundPerBaseColumns);
        welColumnMap.put("otherPerBase", otherPerBaseColumns);
        welColumnMap.put("socialComBase", socialComBaseColumns);
        welColumnMap.put("fundComBase", fundComBaseColumns);
        welColumnMap.put("otherComBase", otherComBaseColumns);
        welColumnMap.put("socialBase", socialBaseColumns);
        welColumnMap.put("fundBase", fundBaseColumns);
        welColumnMap.put("otherBase", otherBaseColumns);
        welColumnMap.put("socialPer", socialPerColumns);
        welColumnMap.put("fundPer", fundPerColumns);
        welColumnMap.put("otherPer", otherPerColumns);
        welColumnMap.put("socialCom", socialComColumns);
        welColumnMap.put("fundCom", fundComColumns);
        welColumnMap.put("otherCom", otherComColumns);
        return welColumnMap;
    }

    public Map<String, String> welColumnNameCodeMap(InsuranceAccountDetailParam param) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();
        //查询线上福利核算记录
        InsuranceExportParam insuranceExportParam = new InsuranceExportParam();
        insuranceExportParam.setBillMonth(param.getBillMonth());
        insuranceExportParam.setPaymentOrganization(param.getPaymentOrganization());
        List<AccountExportPO> accountExportPOS = getInsuranceExportMapper().exportAccount(param.getPaymentStatus(), insuranceExportParam);

        //整理线上核算记录相关的福利方案，并以此整理需要对比的福利项类别数据
        Set<Long> welfareSchemeIds = new HashSet<>();
        accountExportPOS.forEach(f -> {
            welfareSchemeIds.add(f.getSocialSchemeId());
            welfareSchemeIds.add(f.getFundSchemeId());
            welfareSchemeIds.add(f.getOtherSchemeId());
        });
        List<InsuranceSchemeDetailPO> insuranceSchemeDetailPos = getInsuranceSchemeDetailMapper().listAll();
        List<Long> insuranceBaseIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        List<Long> insurancePerPayIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1 && f.getPaymentScope() == 2)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        List<Long> insuranceComPayIds = insuranceSchemeDetailPos.stream()
                .filter(f -> welfareSchemeIds.contains(f.getPrimaryId()) && f.getIsPayment() == 1 && f.getPaymentScope() == 1)
                .map(InsuranceSchemeDetailPO::getInsuranceId)
                .collect(Collectors.toList());
        Set<Long> insuranceBaseSet = new HashSet<>(insuranceBaseIds);
        Set<Long> insurancePerPaySet = new HashSet<>(insurancePerPayIds);
        Set<Long> insuranceComPaySet = new HashSet<>(insuranceComPayIds);

        List<ICategoryPO> listAll = getICategoryMapper().listAll();
        List<ICategoryPO> socialWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelfareList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insuranceBaseSet.contains(e.getId())).collect(Collectors.toList());

        List<ICategoryPO> socialWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelPerList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insurancePerPaySet.contains(e.getId())).collect(Collectors.toList());

        List<ICategoryPO> socialWelComList = listAll.stream().filter(e -> e.getWelfareType() == 1 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> fundWelComList = listAll.stream().filter(e -> e.getWelfareType() == 2 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());
        List<ICategoryPO> otherWelComList = listAll.stream().filter(e -> e.getWelfareType() == 3 && e.getIsUse() == 1 && insuranceComPaySet.contains(e.getId())).collect(Collectors.toList());

        //组装社保基数
        Map<String, String> result = new HashMap<>();
        if (welBaseDiffSign) {
            for (ICategoryPO po : socialWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"个人"), po.getId() + "socialPerBase");
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"单位"), po.getId() + "socialComBase");
            }
        } else {
            for (ICategoryPO po : socialWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数"), po.getId() + "socialBase");
            }
        }

        //组装公积金基数
        if (welBaseDiffSign) {
            for (ICategoryPO po : fundWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"个人"), po.getId() + "fundPerBase");
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"单位"), po.getId() + "fundComBase");
            }
        } else {
            for (ICategoryPO po : fundWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数"), po.getId() + "fundBase");
            }
        }

        //组装其他福利基数
        if (welBaseDiffSign) {
            for (ICategoryPO po : otherWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"个人"), po.getId() + "otherPerBase");
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数")
                        + SalaryI18nUtil.getI18nLabel(0,"单位"), po.getId() + "otherComBase");
            }
        } else {
            for (ICategoryPO po : otherWelfareList) {
                result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                        + SalaryI18nUtil.getI18nLabel(0, "申报基数"), po.getId() + "otherBase");
            }
        }

        //社保个人（生育保险个人、工伤保险个人、失业保险个人、养老保险个人、医疗保险个人）
        for (ICategoryPO po : socialWelPerList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "个人"), po.getId() + "socialPer");
        }
        //住房公积金个人、补充住房公积金个人
        for (ICategoryPO po : fundWelPerList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "个人"), po.getId() + "fundPer");
        }
        //其他个人（比如企业年金个人）
        for (ICategoryPO po : otherWelPerList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "个人"), po.getId() + "otherPer");
        }
        //社保单位（生育保险单位、工伤保险单位、失业保险单位、养老保险单位、医疗保险单位）
        for (ICategoryPO po : socialWelComList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "单位"), po.getId() + "socialCom");
        }
        //住房公积金单位、补充住房公积金单位
        for (ICategoryPO po : fundWelComList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "单位"), po.getId() + "fundCom");
        }

        //其他单位（比如企业年金单位）
        for (ICategoryPO po : otherWelComList) {
            result.put(Util.formatMultiLang(po.getInsuranceName(), String.valueOf(user.getLanguage()))
                    + SalaryI18nUtil.getI18nLabel(0, "单位"), po.getId() + "otherCom");
        }

        return result;
    }

    /**
     * 将通过“福利核算-线下对比导入”模板导入的数据更新到hrsa_excel_bill_detail表中
     */
    @Override
    public Map<String, Object> importExcelInsuranceDetail(ExcelInsuranceImportParam importParam) {

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

        //查询对于人员信息导入筛选的全局配置
        SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
        String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";
        //检验参数
        //excel文件id
        String imageId = Util.null2String(importParam.getImageId());

        if (StringUtils.isBlank(imageId)) {
            throw new SalaryRunTimeException("文件不存在");
        }

        // 获取租户下所有的人员
        List<DataCollectionEmployee> salaryEmployees = getSalaryEmployeeService(user).listAll(UseEmployeeTypeEnum.ALL);

        // 失败的数量
        int failCount = 0;
        // 成功的数量
        int successCount = 0;
        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(importParam.getImageId()));

            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);

            // 错误提示信息
            List<Map> excelComments = Lists.newArrayList();
            // 存在错误的那行数据
            List<Map<String, Object>> errorDatas = Lists.newArrayList();
            // 表头
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);
            // 处理数值
            List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 1);
            if (CollectionUtils.isEmpty(headers)) {
                throw new SalaryRunTimeException("表头为空");
            }
            if (CollectionUtils.isEmpty(data)) {
                throw new SalaryRunTimeException("无数据");
            }

            String billMonth = importParam.getBillMonth();

//            Map<String, String> welColumnNameCodeMap = welColumnNameCodeMap(InsuranceAccountDetailParam.builder()
//                    .billMonth(billMonth)
//                    .paymentOrganization(importParam.getPaymentOrganization())
//                    .paymentStatus(PaymentStatusEnum.COMMON.getValue())
//                    .build());
            Map<String, String> welColumnNameCodeMap = new HashMap<>();
            //存储待更新的InsuranceAccountDetailPO数据
            List<ExcelInsuranceDetailPO> addCompareList = new ArrayList<>();
            //记录待删除hrsa_excel_bill_detail.id
            List<Long> idList = new ArrayList<>();
            //遍历excel表具体数据
            for (int i = 0; i < data.size(); i++) {

                String row = "第" + (i + 2) + "行";

                boolean isError = false;
                Map<String, Object> map = data.get(i);
                Long employeeId = 0L;

                List<ExcelInsuranceDetailPO> list = new ArrayList<>();

                String taxAgentName = (String) map.getOrDefault("个税扣缴义务人", "");
                Long paymentOrganization = 0L;
                List<TaxAgentPO> taxAgentPoList = getTaxAgentMapper().listByName(taxAgentName);

                if (taxAgentPoList.size() == 1) {
                    paymentOrganization = taxAgentPoList.get(0).getId();
                    welColumnNameCodeMap = welColumnNameCodeMap(InsuranceAccountDetailParam.builder()
                            .billMonth(billMonth)
                            .paymentOrganization(paymentOrganization.toString())
                            .paymentStatus(PaymentStatusEnum.COMMON.getValue())
                            .build());
                } else {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, SalaryI18nUtil.getI18nLabel(102840, "个税扣缴义务人错误，系统内不存在该个税扣缴义务人")));
                    excelComments.add(errorMessageMap);
                }

                //遍历表头
                for (int j = 0; j < headers.size(); j++) {
                    String header = headers.get(j);
                    String dataKey = header;
                    if (dataKey == null) {
                        continue;
                    }
                    String dataValue = (String) map.getOrDefault(dataKey.toString(), "");
                    String deparmentName = (String) map.getOrDefault("部门", "");
                    String mobile = (String) map.getOrDefault("手机号", "");
                    String workcode = (String) map.getOrDefault("工号", "");
                    String idNo = (String) map.getOrDefault("证件号码", "");


                    if (StringUtils.equals(SalaryI18nUtil.getI18nLabel(85429, "姓名"), dataKey.toString())) {
                        //当人员信息导入筛选的全局配置为"0"时，姓名才是必填项
                        if (StringUtils.isEmpty(dataValue) && "0".equals(confValue)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(102838, "姓名不能为空"));
                            excelComments.add(errorMessageMap);

                        } else {
                            //筛选导入人员信息可以在人力资源池中匹配到的人员信息
                            List<DataCollectionEmployee> employeeSameIds = getSalaryEmployeeService(user).matchImportEmployee(confValue,salaryEmployees, dataValue, deparmentName, mobile, workcode, idNo,null);

                            if (CollectionUtils.isEmpty(employeeSameIds)) {
                                isError = true;
                                Map<String, String> errorMessageMap = Maps.newHashMap();
                                errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "姓名错误，系统内不存在该姓名"));
                                excelComments.add(errorMessageMap);

                            } else if (employeeSameIds.size() > 1) {
                                //存在离职和在职状态取在职状态
                                employeeSameIds = employeeSameIds.stream()
                                        .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
                                        .collect(Collectors.toList());
                                if (employeeSameIds.size() != 1) {
                                    isError = true;
                                    Map<String, String> errorMessageMap = Maps.newHashMap();
                                    errorMessageMap.put("message", row + "员工信息不存在或者存在多个员工");
                                    excelComments.add(errorMessageMap);
                                } else {
                                    employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0).getEmployeeId() : null;
                                }
                            } else {
                                employeeId = employeeSameIds.get(0).getEmployeeId();
                            }
                        }
                    }


                }

                if (!isError){
                    List<Long> employeeIds = new ArrayList<>();
                    employeeIds.add(employeeId);
                    //根据员工id、个税扣缴义务人id、账单月份查询，如果当前对比表中存在数据，则记录为待删除数据
                    list = getExcelInsuranceDetailMapper().queryCompareList(billMonth, paymentOrganization, employeeIds.get(0));

                    if (!list.isEmpty()) {
                        List<Long> ids = list.stream().map(ExcelInsuranceDetailPO::getId)
                                .collect(Collectors.toList());

                        idList.addAll(ids);
                    }
                    //拼装待更新数据
                    addCompareList.add(handleExcelInsuranceDetail(billMonth, employeeId, paymentOrganization, map, welColumnNameCodeMap));

                }

                if (isError) {
                    failCount++;
                    errorDatas.add(map);
                } else {
                    successCount++;
                }

            }
            //将待更新列表加密
            encryptUtil.encryptList(addCompareList, ExcelInsuranceDetailPO.class);
            //删除
            if (idList.size() > 0) {
                getExcelInsuranceDetailMapper().batchDelByIds(idList);
            }
            //新增
            List<List<ExcelInsuranceDetailPO>> partition = Lists.partition((List<ExcelInsuranceDetailPO>) addCompareList, 20);
            partition.forEach(getExcelInsuranceDetailMapper()::batchSave);

//            getExcelInsuranceDetailMapper().batchSave(addCompareList);

            apidatas.put("successCount", successCount);
            apidatas.put("errorCount", failCount);
            apidatas.put("errorData", excelComments);

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

    /**
     * 将excel导入的数据行组装成ExcelInsuranceDetailPO对象
     * @param billMonth 对比的账单月份
     * @param baseMap excel导入的对比数据
     */
    private ExcelInsuranceDetailPO handleExcelInsuranceDetail(String billMonth, Long employeeId, Long paymentOrganization, Map<String, Object> baseMap, Map<String, String> welColumnNameCodeMap) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();

        ExcelInsuranceDetailPO excelInsuranceDetailPO = new ExcelInsuranceDetailPO();
        excelInsuranceDetailPO.setId(IdGenerator.generate());
        //组装json数据,格式Map<String, Object>
        Map<String, String> socialPerMap = new HashMap<>();
        Map<String, String> fundPerMap = new HashMap<>();
        Map<String, String> otherPerMap = new HashMap<>();
        Map<String, String> socialComMap = new HashMap<>();
        Map<String, String> fundComMap = new HashMap<>();
        Map<String, String> otherComMap = new HashMap<>();
        //组装福利基数
        Map<String, String> socialPaymentBaseMap = new HashMap<>();
        Map<String, String> fundPaymentBaseMap = new HashMap<>();
        Map<String, String> otherPaymentBaseMap = new HashMap<>();

        Map<String, String> socialPaymentComBaseMap = new HashMap<>();
        Map<String, String> fundPaymentComBaseMap = new HashMap<>();
        Map<String, String> otherPaymentComBaseMap = new HashMap<>();

        //筛选出福利核算项
        Map<String, Object> toDealMap =
                baseMap.entrySet().stream()
                        .filter(map -> !"姓名".equals(map.getKey())
                                && !"部门".equals(map.getKey())
                                && !"手机号".equals(map.getKey())
                                && !"个税扣缴义务人".equals(map.getKey())
                                && !"员工状态".equals(map.getKey())
                                && !"数据来源".equals(map.getKey())
                                && !"工号".equals(map.getKey()))
                        .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));

        for(Map.Entry<String, Object> entry : toDealMap.entrySet()) {
//            //判断元素是否属于福利类
//            String keyName = entry.getKey();
//            //获取元素名后缀，方便之后判断“个人”或“单位”或者“基数”
//            String payScope = keyName.substring(keyName.length() - 2);
//            //获取福利类型
//            Integer welfareType;
//            //根据元素名后缀，区分截取内容
//            String targetWelfareName;
//            if ("基数".equals(payScope)) {
//                targetWelfareName = entry.getKey().substring(0, keyName.length() - 4);
//            } else {
//                targetWelfareName = entry.getKey().substring(0, keyName.length() - 2);
//            }
//            List<ICategoryPO> categoryPOList = siCategoryBiz.listByName(targetWelfareName);
//            if (categoryPOList.size() == 1) {
//                ICategoryPO iCategoryPO = categoryPOList.get(0);
//                welfareType = iCategoryPO.getWelfareType();
//
//                switch (payScope) {
//                    case "个人":
//                        switch (welfareType) {
//                            case 1:
//                                socialPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 2:
//                                fundPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 3:
//                                otherPerMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            default:
//                                throw new SalaryRunTimeException("福利类型不存在");
//                        }
//                        break;
//                    case "单位":
//                        switch (welfareType) {
//                            case 1:
//                                socialComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 2:
//                                fundComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 3:
//                                otherComMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            default:
//                                throw new SalaryRunTimeException("福利类型不存在");
//                        }
//                        break;
//                    case "基数":
//                        switch (welfareType) {
//                            case 1:
//                                socialPaymentBaseMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 2:
//                                fundPaymentBaseMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            case 3:
//                                otherPaymentBaseMap.put(iCategoryPO.getId().toString(), entry.getValue().toString());
//                                break;
//                            default:
//                                throw new SalaryRunTimeException("福利类型不存在");
//                        }
//                        break;
//                }
//            }

            if (welColumnNameCodeMap.get(entry.getKey()) != null) {
                String code = welColumnNameCodeMap.get(entry.getKey());
                if (welBaseDiffSign) {
                    if (code.contains("socialPerBase")) {
                        code = code.replace("socialPerBase", "");
                        socialPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("socialComBase")) {
                        code = code.replace("socialComBase", "");
                        socialPaymentComBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("fundPerBase")) {
                        code = code.replace("fundPerBase", "");
                        fundPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("fundComBase")) {
                        code = code.replace("fundComBase", "");
                        fundPaymentComBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("otherPerBase")) {
                        code = code.replace("otherPerBase", "");
                        otherPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("otherComBase")) {
                        code = code.replace("otherComBase", "");
                        otherPaymentComBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                } else {
                    if (code.contains("socialBase")) {
                        code = code.replace("socialBase", "");
                        socialPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("fundBase")) {
                        code = code.replace("fundBase", "");
                        fundPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                    if (code.contains("otherBase")) {
                        code = code.replace("otherBase", "");
                        otherPaymentBaseMap.put(code, entry.getValue().toString());
                        continue;
                    }
                }


                if (code.contains("socialPer") && !code.contains("socialPerBase")) {
                    code = code.replace("socialPer", "");
                    socialPerMap.put(code, entry.getValue().toString());
                    continue;
                }
                if (code.contains("fundPer") && !code.contains("fundPerBase")) {
                    code = code.replace("fundPer", "");
                    fundPerMap.put(code, entry.getValue().toString());
                    continue;
                }
                if (code.contains("otherPer") && !code.contains("otherPerBase")) {
                    code = code.replace("otherPer", "");
                    otherPerMap.put(code, entry.getValue().toString());
                    continue;
                }

                if (code.contains("socialCom") && !code.contains("socialComBase")) {
                    code = code.replace("socialCom", "");
                    socialComMap.put(code, entry.getValue().toString());
                    continue;
                }
                if (code.contains("fundCom") && !code.contains("fundComBase")) {
                    code = code.replace("fundCom", "");
                    fundComMap.put(code, entry.getValue().toString());
                    continue;
                }
                if (code.contains("otherCom") && !code.contains("otherComBase")) {
                    code = code.replace("otherCom", "");
                    otherComMap.put(code, entry.getValue().toString());
                    continue;
                }
            }
        }

        //设置社保个人和公司缴纳明细
        excelInsuranceDetailPO.setSocialPerJson(JSON.toJSONString(socialPerMap));
        excelInsuranceDetailPO.setSocialComJson(JSON.toJSONString(socialComMap));
        //设置公积金个人和公司缴纳明细
        excelInsuranceDetailPO.setFundPerJson(JSON.toJSONString(fundPerMap));
        excelInsuranceDetailPO.setFundComJson(JSON.toJSONString(fundComMap));
        //设置其他福利个人和公司缴纳明细
        excelInsuranceDetailPO.setOtherPerJson(JSON.toJSONString(otherPerMap));
        excelInsuranceDetailPO.setOtherComJson(JSON.toJSONString(otherComMap));
        //设置社保、公积金、其他福利缴纳基数
        excelInsuranceDetailPO.setSocialPaymentBaseString(JSON.toJSONString(socialPaymentBaseMap));
        excelInsuranceDetailPO.setFundPaymentBaseString(JSON.toJSONString(fundPaymentBaseMap));
        excelInsuranceDetailPO.setOtherPaymentBaseString(JSON.toJSONString(otherPaymentBaseMap));

        excelInsuranceDetailPO.setSocialPaymentComBaseString(JSON.toJSONString(socialPaymentComBaseMap));
        excelInsuranceDetailPO.setFundPaymentComBaseString(JSON.toJSONString(fundPaymentComBaseMap));
        excelInsuranceDetailPO.setOtherPaymentComBaseString(JSON.toJSONString(otherPaymentComBaseMap));

        //组装新的insuranceAccountDetailPO对象数据
        excelInsuranceDetailPO.setEmployeeId(employeeId);
        excelInsuranceDetailPO.setBillMonth(billMonth);
        excelInsuranceDetailPO.setBillStatus(1);
        excelInsuranceDetailPO.setPaymentStatus(0);
        excelInsuranceDetailPO.setResourceFrom(1);
        excelInsuranceDetailPO.setSocialAccount(baseMap.getOrDefault("社保账号", "").toString());
        if (baseMap.getOrDefault("社保方案名称", "") != null) {
            List<InsuranceSchemePO> socialSchemeList = getInsuranceSchemeMapper().listByName(baseMap.get("社保方案名称").toString());
            if (socialSchemeList.size() == 1) {
                //设置社保方案id
                excelInsuranceDetailPO.setSocialSchemeId(socialSchemeList.get(0).getId());
            }
        }
        excelInsuranceDetailPO.setFundAccount(baseMap.getOrDefault("公积金账号", "").toString());
        excelInsuranceDetailPO.setSupplementFundAccount(baseMap.getOrDefault("补充公积金账号", "").toString());
        if (baseMap.getOrDefault("公积金方案名称", "") != null) {
            List<InsuranceSchemePO> fundSchemeList = getInsuranceSchemeMapper().listByName(baseMap.get("公积金方案名称").toString());
            if (fundSchemeList.size() == 1) {
                //设置公积金方案id
                excelInsuranceDetailPO.setFundSchemeId(fundSchemeList.get(0).getId());
            }
        }
        if (baseMap.getOrDefault("其他福利方案名称", "") != null) {
            List<InsuranceSchemePO> otherSchemeList = getInsuranceSchemeMapper().listByName(baseMap.get("其他福利方案名称").toString());
            if (otherSchemeList.size() == 1) {
                //其他福利方案id
                excelInsuranceDetailPO.setOtherSchemeId(otherSchemeList.get(0).getId());
            }
        }

        excelInsuranceDetailPO.setSocialPerSum(baseMap.getOrDefault("社保个人合计", "").toString());
        excelInsuranceDetailPO.setFundPerSum(baseMap.getOrDefault("公积金个人合计", "").toString());
        excelInsuranceDetailPO.setOtherPerSum(baseMap.getOrDefault("其他福利个人合计", "").toString());
        excelInsuranceDetailPO.setPerSum(baseMap.getOrDefault("个人合计", "").toString());

        excelInsuranceDetailPO.setSocialComSum(baseMap.getOrDefault("社保单位合计", "").toString());
        excelInsuranceDetailPO.setFundComSum(baseMap.getOrDefault("公积金单位合计", "").toString());
        excelInsuranceDetailPO.setOtherComSum(baseMap.getOrDefault("其他福利单位合计", "").toString());
        excelInsuranceDetailPO.setComSum(baseMap.getOrDefault("单位合计", "").toString());

        excelInsuranceDetailPO.setSocialSum(baseMap.getOrDefault("社保合计", "").toString());
        excelInsuranceDetailPO.setFundSum(baseMap.getOrDefault("公积金合计", "").toString());
        excelInsuranceDetailPO.setOtherSum(baseMap.getOrDefault("其他福利合计", "").toString());
        excelInsuranceDetailPO.setTotal(baseMap.getOrDefault("合计", "").toString());

        excelInsuranceDetailPO.setCreator((long) user.getUID());
        excelInsuranceDetailPO.setCreateTime(new Date());
        excelInsuranceDetailPO.setUpdateTime(new Date());
        excelInsuranceDetailPO.setDeleteType(0);
        excelInsuranceDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        excelInsuranceDetailPO.setPaymentOrganization(paymentOrganization);


        return excelInsuranceDetailPO;
    }

    /**
     * 刷新_bill_batch表中的统计信息
     */
    @Override
    public void refreshBillBatch(Long paymentOrganization, String billMonth) {
        ExecutorService taskExecutor = Executors.newCachedThreadPool();
        taskExecutor.execute(() -> {

            if (paymentOrganization != null && billMonth != null) {
                InsuranceAccountDetailParam refreshParam =new InsuranceAccountDetailParam();
                refreshParam.setBillMonth(billMonth);
                refreshParam.setPaymentOrganization(paymentOrganization.toString());
                PageInfo<InsuranceAccountViewListDTO> pageInfos = overView(refreshParam);
                TaxAgentPO taxAgentPo = getTaxAgentMapper().getById(paymentOrganization);
                if (taxAgentPo != null) {
                    List<InsuranceAccountViewListDTO> viewListDTOList = pageInfos.getList();
                    viewListDTOList.stream().filter(f -> f.getPayOrg().equals(taxAgentPo.getName())).collect(Collectors.toList());
                    InsuranceAccountBatchPO batchPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, paymentOrganization);
                    batchPO = encryptUtil.decrypt(batchPO, InsuranceAccountBatchPO.class);
                    //更新
                    if (viewListDTOList.size() > 0 && batchPO != null) {
                        InsuranceAccountViewListDTO viewListDTO = viewListDTOList.get(0);
                        batchPO.setSocialNum(viewListDTO.getSocialNum());
                        batchPO.setFundNum(viewListDTO.getFundNum());
                        batchPO.setOtherNum(viewListDTO.getOtherNum());

                        batchPO.setSocialPay(viewListDTO.getSocialPaySum().replace(",", ""));
                        batchPO.setFundPay(viewListDTO.getFundPaySum().replace(",", ""));
                        batchPO.setOtherPay(viewListDTO.getOtherPaySum().replace(",", ""));

                        batchPO.setUpdateTime(new Date());
                        batchPO = encryptUtil.encrypt(batchPO, InsuranceAccountBatchPO.class);
                        getInsuranceAccountBatchMapper().updateById(batchPO);
                    }
                }

            }
        });
    }
    /**
     * 将通过id获取InsuranceAccountDetailPO中的社保、公积金、其他福利个人和公司缴纳数据
     */
    @Override
    public Map<String, Object> getPaymentById(Long id) {

        InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(id);
        if (insuranceAccountDetailPO == null) {
            throw new SalaryRunTimeException("该条核算数据不存在！");
        }
        encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
        String socialPerJson = insuranceAccountDetailPO.getSocialPerJson();
        String socialComJson = insuranceAccountDetailPO.getSocialComJson();
        String fundPerJson = insuranceAccountDetailPO.getFundPerJson();
        String fundComJson = insuranceAccountDetailPO.getFundComJson();
        String otherPerJson = insuranceAccountDetailPO.getOtherPerJson();
        String otherComJson = insuranceAccountDetailPO.getOtherComJson();

        Map<String, String> dataMap = new HashMap<>();
        List<SearchConditionGroup> addGroups = new ArrayList<>();

        getPaymentGroup(socialPerJson, "个人", "社保", dataMap, addGroups);
        getPaymentGroup(socialComJson, "公司", "社保", dataMap, addGroups);
        getPaymentGroup(fundPerJson, "个人", "公积金", dataMap, addGroups);
        getPaymentGroup(fundComJson, "公司", "公积金", dataMap, addGroups);
        getPaymentGroup(otherPerJson, "个人", "其他福利", dataMap, addGroups);
        getPaymentGroup(otherComJson, "公司", "其他福利", dataMap, addGroups);

        Map<String, Object> resultMap = new HashMap<>();
//        resultMap.put("data", dataMap);
//        resultMap.put("items", addGroups);

        List<Map<String, String>> perList = new ArrayList<>();
        List<Map<String, String>> comList = new ArrayList<>();
        for (SearchConditionGroup group : addGroups) {

            if (group.getItems() != null && group.getItems().size() > 0) {
                for (SearchConditionItem item : group.getItems()) {
                    Map<String, String> map = new HashMap<>();

                    String[] domkey = item.getDomkey();
                    String insuranceId = domkey[0].substring(3);
                    if (group.getTitle().contains("个人")) {
                        map.put("title", group.getTitle());
                        map.put("titleSign", getTotalSign(group.getTitle()));
                        map.put("paymentScope", "个人");
                        map.put("paymentScopeSign", "per");
                        map.put("insuranceName", item.getLabel());
                        map.put("insuranceId", insuranceId);
                        map.put("insuranceValue", dataMap.get(domkey[0]));
                        if (map.get("insuranceValue") != null && !"".equals(map.get("insuranceValue"))) {

                            perList.add(map);
                        }

                    } else if (group.getTitle().contains("公司")) {
                        map.put("title", group.getTitle());
                        map.put("titleSign", getTotalSign(group.getTitle()));
                        map.put("paymentScope", "公司");
                        map.put("paymentScopeSign", "com");
                        map.put("insuranceName", item.getLabel());
                        map.put("insuranceId", insuranceId);
                        map.put("insuranceValue", dataMap.get(domkey[0]));
                        if (map.get("insuranceValue") != null && !"".equals(map.get("insuranceValue"))) {

                            comList.add(map);
                        }

                    }
                }
            }

        }

        List<Map<String, String>> resultList = new ArrayList<>();
        resultList.addAll(perList);
        resultList.addAll(comList);
//        resultMap.put("data", resultList);
        //20231123逻辑变更，对于补差的待编辑内容，扩充其人员档案设置的福利项内容
        if (insuranceAccountDetailPO.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
            List<Map<String, String>> balancePaymentGroup = getSIBalanceService(user).getPaymentGroup(BalanceAccountBaseParam.builder()
                    .employeeId(insuranceAccountDetailPO.getEmployeeId())
                    .paymentOrganization(insuranceAccountDetailPO.getPaymentOrganization()).build());
            if (balancePaymentGroup != null && balancePaymentGroup.size() > 0) {
                //抽取已有福利项生成map
                Map<String, Object> targetMap = new HashMap<>();
                for (Map<String, String> resultItem : resultList) {
                    targetMap.put(resultItem.get("insuranceId") + "-" + resultItem.get("paymentScope"), resultItem);
                }
                //对比可进行缴纳福利项与上面的已有福利项生成map
                for (Map<String, String> balancePayItem : balancePaymentGroup) {
                    if (targetMap.get(balancePayItem.get("insuranceId") + "-" + balancePayItem.get("paymentScope")) == null) {
                        balancePayItem.put("insuranceValue", "");
                        resultList.add(balancePayItem);
                    }
                }
            }
        }
        resultMap.put("data", resultList);
        return resultMap;
    }

    public String getTotalSign(String total) {
        if (StringUtils.isNotBlank(total)) {
            return total.contains(SalaryI18nUtil.getI18nLabel(0,"社保")) ? "social" : (total.contains(SalaryI18nUtil.getI18nLabel(0,"公积金")) ? "fund" : "other" );
        } else {
            return "";
        }
    }
    public void getPaymentGroup(String baseJson, String groupType, String welfareType, Map<String, String> dataMap, List<SearchConditionGroup> addGroups) {

        if (StringUtils.isBlank(baseJson)) {
            addGroups.add(new SearchConditionGroup(welfareType + groupType +"缴纳", true, null));
            return;
        }

        String groupPrefix = "个人".equals(groupType) ? "per" : "com";

        Map<String, String> toDealMap = JSON.parseObject(baseJson, new HashMap<String, String>().getClass());
        Map<String, String> baseJsonMap = new HashMap<>();
        List<SearchConditionItem> inputItems = new ArrayList<>();

        for (Map.Entry<String, String> entry : toDealMap.entrySet()) {
            //获取福利项信息
//            ICategoryPO iCategoryPO = siCategoryBiz.getByID(Long.valueOf(entry.getKey()));
            ICategoryPO iCategoryPO = getSICategoryService(user).getICategoryPOByID(Long.valueOf(entry.getKey()));
            if (iCategoryPO != null) {
                String name = groupPrefix + iCategoryPO.getId().toString();
                String label = iCategoryPO.getInsuranceName();
                inputItems.add(SalaryFormItemUtil.inputNumberItem(user, "precision:2", 2, 12, 2, label, name));
            }
            baseJsonMap.put(groupPrefix + entry.getKey(), entry.getValue());
        }
        dataMap.putAll(baseJsonMap);
        addGroups.add(new SearchConditionGroup(welfareType + groupType +"缴纳", true, inputItems));
    }

    /**
     * 编辑InsuranceAccountDetailPO中的社保、公积金、其他福利个人和公司缴纳数据
     */
    @Override
    public void editAccount(EditAccountDetailParam param) {
        InsuranceAccountDetailPO insuranceAccountDetailPO = getInsuranceAccountDetailMapper().getById(param.getId());
        if (insuranceAccountDetailPO == null) {
            throw new SalaryRunTimeException("该条核算数据不存在！");
        }
        encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);

        InsuranceAccountDetailPO oldTargetPO = new InsuranceAccountDetailPO();
        BeanUtils.copyProperties(insuranceAccountDetailPO, oldTargetPO);

        accountSocialByData(insuranceAccountDetailPO, param);
        accountFundByData(insuranceAccountDetailPO, param);
        accountOtherByData(insuranceAccountDetailPO, param);
        account(insuranceAccountDetailPO);

        encryptUtil.encrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
        getInsuranceAccountDetailMapper().updateById(insuranceAccountDetailPO);

        //刷新_bill_batch表中的统计信息
        refreshBillBatch(insuranceAccountDetailPO.getPaymentOrganization(), insuranceAccountDetailPO.getBillMonth());
        //记录操作日志
        PaymentStatusEnum targetEnum = SalaryEnumUtil.enumMatchByValue(insuranceAccountDetailPO.getPaymentStatus(), PaymentStatusEnum.values(), PaymentStatusEnum.class);
        encryptUtil.decrypt(insuranceAccountDetailPO, InsuranceAccountDetailPO.class);
        InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(insuranceAccountDetailPO.getBillMonth(), insuranceAccountDetailPO.getPaymentOrganization());
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
        DataCollectionEmployee empInfo = getEmployMapper().getEmployeeById(insuranceAccountDetailPO.getEmployeeId());
        LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(targetPO.getId()));
        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth() + "-" + empInfo.getUsername());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-编辑")
                + SalaryI18nUtil.getI18nLabel(targetEnum.getLabelId(), targetEnum.getDefaultLabel()));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-编辑"
                + SalaryI18nUtil.getI18nLabel(targetEnum.getLabelId(), targetEnum.getDefaultLabel()))
                + ":" + taxAgentInfo.getName() + "-" + targetPO.getBillMonth() + "-" + empInfo.getUsername());
        loggerContext.setOldValues(oldTargetPO);
        loggerContext.setNewValues(insuranceAccountDetailPO);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
    }

    public void accountFundByData(InsuranceAccountDetailPO insuranceAccountDetailPO, EditAccountDetailParam baseParam) {
        //公积金个人
        if (StringUtils.isNotBlank(baseParam.getFundPerJson())) {
            List<BigDecimal> fundPer = new ArrayList<>();
            HashMap<String, String> fundPerson = JSON.parseObject(baseParam.getFundPerJson(), new HashMap<String, String>().getClass());
            fundPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundPer.add(result);
            });
            insuranceAccountDetailPO.setFundPerJson(baseParam.getFundPerJson());
            BigDecimal fundPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundPer) {
                fundPerSum = fundPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundPerSum(fundPerSum.toPlainString());
        }
        //公积金单位
        if (StringUtils.isNotBlank(baseParam.getFundComJson())) {
            List<BigDecimal> fundCom = new ArrayList<>();
            HashMap<String, String> fundComMap = JSON.parseObject(baseParam.getFundComJson(), new HashMap<String, String>().getClass());
            fundComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundCom.add(result);
            });
            insuranceAccountDetailPO.setFundComJson(baseParam.getFundComJson());
            BigDecimal fundComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundCom) {
                fundComSum = fundComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());
        }
    }

    public void accountOtherByData(InsuranceAccountDetailPO insuranceAccountDetailPO, EditAccountDetailParam baseParam) {
        //其他福利个人
        if (StringUtils.isNotBlank(baseParam.getOtherPerJson())) {
            List<BigDecimal> otherPer = new ArrayList<>();
            HashMap<String, String> otherPerMap = JSON.parseObject(baseParam.getOtherPerJson(), new HashMap<String, String>().getClass());
            otherPerMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherPer.add(result);
            });
            insuranceAccountDetailPO.setOtherPerJson(baseParam.getOtherPerJson());
            BigDecimal otherPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherPer) {
                otherPerSum = otherPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());
        }
        //其他福利单位
        if (StringUtils.isNotBlank(baseParam.getOtherComJson())) {
            List<BigDecimal> otherCom = new ArrayList<>();
            HashMap<String, String> otherComMap = JSON.parseObject(baseParam.getOtherComJson(), new HashMap<String, String>().getClass());
            otherComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherCom.add(result);
            });
            insuranceAccountDetailPO.setOtherComJson(baseParam.getOtherComJson());
            BigDecimal otherComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherCom) {
                otherComSum = otherComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
        }
    }

    public void accountSocialByData(InsuranceAccountDetailPO insuranceAccountDetailPO, EditAccountDetailParam baseParam) {
        //社保个人
        if (StringUtils.isNotBlank(baseParam.getSocialPerJson())) {
            List<BigDecimal> socialPer = new ArrayList<>();
            HashMap<String, String> archivesPerson = JSON.parseObject(baseParam.getSocialPerJson(), new HashMap<String, String>().getClass());
            archivesPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialPer.add(result);
            });
            insuranceAccountDetailPO.setSocialPerJson(baseParam.getSocialPerJson());
            BigDecimal socialPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialPer) {
                socialPerSum = socialPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
        }
        //社保单位
        if (StringUtils.isNotBlank(baseParam.getSocialComJson())) {
            List<BigDecimal> socialCom = new ArrayList<>();
            HashMap<String, String> archivesCom = JSON.parseObject(baseParam.getSocialComJson(), new HashMap<String, String>().getClass());
            archivesCom.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialCom.add(result);
            });
            insuranceAccountDetailPO.setSocialComJson(baseParam.getSocialComJson());
            BigDecimal socialComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialCom) {
                socialComSum = socialComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        }
    }

    public InsuranceAccountDetailPO account(InsuranceAccountDetailPO insuranceAccountDetailPO) {
        //个人合计
        BigDecimal socialPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getSocialPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getSocialPerSum());
        BigDecimal fundPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getFundPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getFundPerSum());
        BigDecimal otherPerson =
                StringUtils.isBlank(insuranceAccountDetailPO.getOtherPerSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getOtherPerSum());
        BigDecimal perSum = socialPerson.add(fundPerson).add(otherPerson);
        insuranceAccountDetailPO.setPerSum(perSum.toPlainString());
        //单位合计
        BigDecimal socialCom =
                StringUtils.isBlank(insuranceAccountDetailPO.getSocialComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getSocialComSum());
        BigDecimal fundCom = StringUtils.isBlank(insuranceAccountDetailPO.getFundComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getFundComSum());
        BigDecimal otherCom =
                StringUtils.isBlank(insuranceAccountDetailPO.getOtherComSum()) ? new BigDecimal("0") : new BigDecimal(insuranceAccountDetailPO.getOtherComSum());
        BigDecimal comSum = socialCom.add(fundCom).add(otherCom);
        insuranceAccountDetailPO.setComSum(comSum.toPlainString());
        //社保合计
        insuranceAccountDetailPO.setSocialSum(socialPerson.add(socialCom).toPlainString());
        //公积金合计
        insuranceAccountDetailPO.setFundSum(fundPerson.add(fundCom).toPlainString());
        //其他福利合计
        insuranceAccountDetailPO.setOtherSum(otherPerson.add(otherCom).toPlainString());
        //合计
        insuranceAccountDetailPO.setTotal(perSum.add(comSum).toPlainString());
        return insuranceAccountDetailPO;
    }

    /**
     * 导出“福利核算-补差导入”模板
     */
    @Override
    public XSSFWorkbook exportBalanceImportTemplate(InsuranceAcctDetailImportTemplateParam param) {
        ValidUtil.doValidator(param);

        // 必须选择导入模板所需的薪资项目(福利项)
        if (CollectionUtils.isEmpty(param.getWelfareNames())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(99019, "参数错误，请选择导入模板所需的福利项目核算项"));
        }

        // 模板表头(默认必带"个税扣缴义务人"、"姓名")
        List<Object> headerList = Lists.newArrayList(SalaryI18nUtil.getI18nLabel(85429, "姓名"),
                "部门",
                SalaryI18nUtil.getI18nLabel(86186, "手机号"),
                SalaryI18nUtil.getI18nLabel(86317, "工号"),
                SalaryI18nUtil.getI18nLabel(86184, "个税扣缴义务人")
                );
        List<String> dataIndexList = Lists.newArrayList("username", "departmentName", "mobile", "workcode", "taxAgentName");
        // 查询福利核算项目
        List<String> welfareNames = (List<String>) param.getWelfareNames();
        headerList.addAll(welfareNames);

//        //查询当前已有的补缴数据
//        List<Map<String, Object>> resultMapList = getSupplyDataByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
//        // excel导出的数据
//        List<List<Object>> rows = Lists.newArrayListWithExpectedSize(resultMapList.size());
//        rows.add(headerList);
//        for (Map<String, Object> map : resultMapList) {
//            List<Object> row = Lists.newArrayListWithExpectedSize(headerList.size());
//            for (String dataIndex : dataIndexList) {
//                row.add(map.getOrDefault(dataIndex, StringUtils.EMPTY));
//            }
//            rows.add(row);
//        }

        List<List<Object>> rows = new ArrayList<>();
        rows.add(headerList);

        String sheetName = "福利核算-补差导入模板";
        return ExcelUtil.genWorkbookV2(rows, sheetName);
    }

    /**
     * 将福利台账-补差模板导入的数据更新到数据库
     */
    @Override
    public Map<String, Object> importBalanceInsuranceDetail(InsuranceAcctImportParam importParam) {
        long currentEmployeeId = user.getUID();
//        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();

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

        //查询对于人员信息导入筛选的全局配置
        SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
        String confValue = (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";
        //检验参数
        //excel文件id
        String imageId = Util.null2String(importParam.getImageId());

        if (StringUtils.isBlank(imageId)) {
            throw new SalaryRunTimeException("文件不存在");
        }
//        // 获取所有个税扣缴义务人
//        List<TaxAgentPO> taxAgents = getTaxAgentService(user).listAll();
//        Map<String, Long> taxAgentNameMap = SalaryEntityUtil.convert2Map(taxAgents, TaxAgentPO::getName, TaxAgentPO::getId);

        // 获取租户下所有的人员
        List<DataCollectionEmployee> salaryEmployees = getSalaryEmployeeService(user).listEmployee();

        List<ICategoryPO> insuranceCategoryPOS = getICategoryMapper().listAll();
        // 失败的数量
        int failCount = 0;
        // 成功的数量
        int successCount = 0;
        InputStream fileInputStream = null;
        try {
            fileInputStream = ImageFileManager.getInputStreamById(Integer.parseInt(importParam.getImageId()));

            Sheet sheet = ExcelSupport.parseFile(fileInputStream, 0, EXCEL_TYPE_XLSX);

            // 错误提示信息
            List<Map> excelComments = Lists.newArrayList();
            // 存在错误的那行数据
            List<Map<String, Object>> errorDatas = Lists.newArrayList();
            // 表头
            List<String> headers = ExcelSupport.getSheetHeader(sheet, 0);
            // 处理数值
            List<Map<String, Object>> data = ExcelParseHelper.parse2Map(sheet, 1);
            if (CollectionUtils.isEmpty(headers)) {
                throw new SalaryRunTimeException("表头为空");
            }
            if (CollectionUtils.isEmpty(data)) {
                throw new SalaryRunTimeException("无数据");
            }
            //存储待更新的InsuranceAccountDetailPO数据
            List<InsuranceAccountDetailPO> updateInsuranceAccountDetailList = new ArrayList<>();

            //存储待新增的InsuranceAccountDetailPO数据
            List<InsuranceAccountDetailPO> createInsuranceAccountDetailList = new ArrayList<>();

            String billMonth = importParam.getBillMonth();
            //遍历excel表具体数据
            for (int i = 0; i < data.size(); i++) {

                String row = "第" + (i + 2) + "行";

                boolean isError = false;
                Map<String, Object> map = data.get(i);
                Long employeeId = 0L;
//                Long taxAgentId = 0L;

                List<InsuranceAccountDetailPO> list = new ArrayList<>();


                String taxAgentName = (String) map.getOrDefault("个税扣缴义务人", "");

                Long paymentOrganization = 0L;
                List<TaxAgentPO> taxAgentPoList = getTaxAgentMapper().listByName(taxAgentName);

                if (taxAgentPoList.size() == 1) {
                    paymentOrganization = taxAgentPoList.get(0).getId();
                } else {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, SalaryI18nUtil.getI18nLabel(102840, "个税扣缴义务人错误，系统内不存在该个税扣缴义务人")));
                    excelComments.add(errorMessageMap);
                }

                if (billMonth.length() < 7 || !SalaryDateUtil.checkYearMonth(billMonth.substring(0, 7))) {
                    isError = true;
                    Map<String, String> errorMessageMap = Maps.newHashMap();
                    errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "账单月份输入有误，请参照“2022-09”这种格式进行检查"));
                    excelComments.add(errorMessageMap);
                }

                List<Map<String, Object>> singleAccount = new ArrayList<>();

                //遍历表头
                for (int j = 0; j < headers.size(); j++) {
                    String header = headers.get(j);
                    String dataKey = header;
                    if (dataKey == null) {
                        continue;
                    }
                    //组装单条数据基础数据
                    Map<String, Object> cellData = new HashMap<>();
                    cellData.put(dataKey, Optional.ofNullable(map.get(dataKey)).orElse("").toString());
                    cellData.put("index", j);
                    singleAccount.add(cellData);
                    //抽取人员信息进行校验
                    String name = (String) map.getOrDefault("姓名", "");
                    String departmentName = (String) map.getOrDefault("部门", "");
                    String mobile = (String) map.getOrDefault("手机号", "");
                    String workcode = (String) map.getOrDefault("工号", "");
                    String idNo = (String) map.getOrDefault("证件号码", "");


                    if (StringUtils.equals(SalaryI18nUtil.getI18nLabel(85429, "姓名"), dataKey.toString())) {
                        //当人员信息导入筛选的全局配置为"0"时，姓名才是必填项
                        if (StringUtils.isEmpty(name) && "0".equals(confValue)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(102838, "姓名不能为空"));
                            excelComments.add(errorMessageMap);

                        } else {
                            //筛选导入人员信息可以在人力资源池中匹配到的人员信息
                            List<DataCollectionEmployee> employeeSameIds = getSalaryEmployeeService(user).matchImportEmployee(confValue,salaryEmployees, name, departmentName, mobile, workcode,idNo, null);

                            if (CollectionUtils.isEmpty(employeeSameIds)) {
                                isError = true;
                                Map<String, String> errorMessageMap = Maps.newHashMap();
                                errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579, "姓名错误，系统内不存在该姓名"));
                                excelComments.add(errorMessageMap);

                            } else if (employeeSameIds.size() > 1) {
                                //存在离职和在职状态取在职状态
                                employeeSameIds = employeeSameIds.stream()
                                        .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
                                        .collect(Collectors.toList());
                                if (employeeSameIds.size() != 1) {
                                    isError = true;
                                    Map<String, String> errorMessageMap = Maps.newHashMap();
                                    errorMessageMap.put("message", row + "员工信息不存在或者存在多个员工");
                                    excelComments.add(errorMessageMap);
                                } else {
                                    employeeId = CollectionUtils.isNotEmpty(employeeSameIds) && employeeSameIds.size() == 1 ? employeeSameIds.get(0).getEmployeeId() : null;
                                }
                            } else {
                                employeeId = employeeSameIds.get(0).getEmployeeId();
                            }
                        }
                    }


                }

                if (!isError){

                    //如果福利核算信息查询不到唯一匹配数据，不支持导入
                    //根据员工id、个税扣缴义务人id、账单月份查询补差数据
                    list = getInsuranceAccountDetailMapper().queryBalanceList(InsuranceAccountDetailPO.builder()
                            .employeeId(employeeId)
                            .paymentOrganization(paymentOrganization)
                            .billMonth(billMonth.substring(0, 7))
                            .build());

                    if (list.isEmpty()) {
                        //新增数据情况
                        InsuranceAccountDetailPO createPO =  buildBalanceAccountDetail(paymentOrganization, insuranceCategoryPOS, singleAccount, billMonth, employeeId, currentEmployeeId);

                        if(!checkBalancePayInsurance(createPO)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(0,  "补差数据中存在福利档案中未设置的福利项缴纳数值，请检查补差缴纳信息！"));
                            excelComments.add(errorMessageMap);
                        }

                        if(checkBalance(createPO) && !isError) {
                            createInsuranceAccountDetailList.add(createPO);
                        } else {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579,  "该人员在当前账单月不存在补差数据中的福利类，请检查补差缴纳信息！"));
                            excelComments.add(errorMessageMap);
                        }

                    } else if (list.size() > 1) {
                        isError = true;
                        Map<String, String> errorMessageMap = Maps.newHashMap();
                        errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579,  "该人员在当前账单月已存在多组补差数据，请删除数据库中多余项"));
                        excelComments.add(errorMessageMap);
                    } else {
                        //更新数据情况
                        //拼装待更新数据
                        encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
                        InsuranceAccountDetailPO updatePO = handleInsuranceAccountDetail(list.get(0), map);

                        if(!checkBalancePayInsurance(updatePO)) {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(0,  "补差数据中存在福利档案中未设置的福利项缴纳数值，请检查补差缴纳信息！"));
                            excelComments.add(errorMessageMap);
                        }

                        if(checkBalance(updatePO) && !isError) {
                            updateInsuranceAccountDetailList.add(updatePO);
                        } else {
                            isError = true;
                            Map<String, String> errorMessageMap = Maps.newHashMap();
                            errorMessageMap.put("message", row + SalaryI18nUtil.getI18nLabel(100579,  "该人员在当前账单月不存在补差数据中的福利类，请检查补差缴纳信息！"));
                            excelComments.add(errorMessageMap);
                        }

                    }

                }

                if (isError) {
                    failCount++;
                    errorDatas.add(map);
                } else {
                    successCount++;
                }

            }
            Long paymentOrganization = null;
            if (updateInsuranceAccountDetailList.size() > 0) {
                paymentOrganization = updateInsuranceAccountDetailList.get(0).getPaymentOrganization();
                //将待更新列表加密
                encryptUtil.encryptList(updateInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
                //更新
                for(InsuranceAccountDetailPO po : updateInsuranceAccountDetailList) {
//                    getSiAccountBiz(user).updateByEmployeeIdAndBillMonth(po);
                    updateByEmployeeIdAndBillMonth(po);
                }
                //记录操作日志
                encryptUtil.decryptList(updateInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
                InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, paymentOrganization);
                TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
                LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
                loggerContext.setUser(user);
                loggerContext.setTargetId(String.valueOf(targetPO.getId()));
                loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                loggerContext.setOperateType(OperateTypeEnum.EXCEL_IMPORT.getValue());
                loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-补差导入更新"));
                loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-补差导入更新")
                        + ":" + taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                updateInsuranceAccountDetailList.forEach(loggerContext::setNewValues);
                SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
            }
            if (createInsuranceAccountDetailList.size() > 0) {
                paymentOrganization = createInsuranceAccountDetailList.get(0).getPaymentOrganization();
                //去除员工id+个税扣缴义务人下重复的数据
                createInsuranceAccountDetailList = createInsuranceAccountDetailList.stream()
                        .collect(Collectors.collectingAndThen(Collectors.toCollection(()
                                -> new TreeSet<>(Comparator.comparing(f -> f.getPaymentOrganization() + "-" + f.getEmployeeId()))), ArrayList::new));
                //将待新增列表加密
                encryptUtil.encryptList(createInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
                //新增
                List<List<InsuranceAccountDetailPO>> createPartition = Lists.partition((List<InsuranceAccountDetailPO>) createInsuranceAccountDetailList, 20);
                createPartition.forEach(getInsuranceAccountDetailMapper()::batchSaveAccountDetails);
                //记录操作日志
                encryptUtil.decryptList(createInsuranceAccountDetailList, InsuranceAccountDetailPO.class);
                InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, paymentOrganization);
                TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
                LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
                loggerContext.setUser(user);
                loggerContext.setTargetId(String.valueOf(targetPO.getId()));
                loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                loggerContext.setOperateType(OperateTypeEnum.EXCEL_IMPORT.getValue());
                loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-补差导入新增"));
                loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-补差导入新增")
                        + ":" + taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
                createInsuranceAccountDetailList.forEach(loggerContext::setNewValues);
                SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
            }

            //刷新bill_batch表中统计信息
            refreshBillBatch(paymentOrganization, importParam.getBillMonth());

            apidatas.put("successCount", successCount);
            apidatas.put("errorCount", failCount);
            apidatas.put("errorData", excelComments);

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


    @Override
    public Map<String, Object> listCommonSum(InsuranceAccountDetailParam queryParam) {

        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();

        // 正常缴纳列表
        queryParam.setPageSize(10000000);
//        PageInfo<InsuranceAccountDetailPO> pageInfo = getSiAccountBiz(user).listCommonPage(queryParam);
        PageInfo<InsuranceAccountDetailPO> pageInfo = siBatchListCommonPage(queryParam);
        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = pageInfo.getList();
        // 数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(insuranceAccountDetailPOS, employeeId);
//        Map<String, Object> maxSizeRecord = records.stream().reduce(new HashMap<>(), (a, b) -> a.size() > b.size() ? a : b);
        Map<String, Object> sumRow = countSum(records);
        datas.put("sumRow", sumRow);
        return datas;
    }

    @Override
    public Map<String, Object> listSupplementarySum(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();
        queryParam.setPageSize(10000000);

//        //过滤出福利档案基础信息表中runStatus为正在缴纳和待减员的人员
//        List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
//        List<Long> canAccountIds = baseInfoPOList.stream()
//                .filter(f->f.getPaymentOrganization().toString().equals(queryParam.getPaymentOrganization())
//                        && (f.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()) || f.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue())))
//                .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
//                .collect(Collectors.toList());
//        queryParam.setEmployeeIds(canAccountIds);

        //补缴缴纳列表
        queryParam.setPaymentStatus(PaymentStatusEnum.REPAIR.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(list, employeeId);
//        Map<String, Object> maxSizeRecord = records.stream().reduce(new HashMap<>(), (a, b) -> a.size() > b.size() ? a : b);
        Map<String, Object> sumRow = countSum(records);
        datas.put("sumRow", sumRow);
        return datas;
    }

    @Override
    public Map<String, Object> listRecessionSum(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();
        queryParam.setPageSize(10000000);
        // 分权逻辑
        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        if (needAuth) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgents((long) user.getUID());
            List<Long> taxAgents = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgents)) {
                //防止普通用户查询
                queryParam.setTaxAgents(Collections.singletonList(-1L));
            } else {
                queryParam.setTaxAgents(taxAgents);
            }
        }

        //退差列表
        queryParam.setPaymentStatus(PaymentStatusEnum.RECESSION.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(list, employeeId);
        Map<String, Object> sumRow = countSum(records);
        datas.put("sumRow", sumRow);
        return datas;
    }

    @Override
    public Map<String, Object> listBalanceSum(InsuranceAccountDetailParam queryParam) {
        Long employeeId = (long) user.getUID();
        Map<String, Object> datas = new HashMap<>();
        queryParam.setPageSize(10000000);
        // 分权逻辑
        Boolean needAuth = getTaxAgentService(user).isNeedAuth((long) user.getUID());
        if (needAuth) {
            Collection<TaxAgentPO> taxAgentPOS = getTaxAgentService(user).listAllTaxAgents((long) user.getUID());
            List<Long> taxAgents = taxAgentPOS.stream().map(TaxAgentPO::getId).collect(Collectors.toList());
            if (CollectionUtils.isEmpty(taxAgents)) {
                //防止普通用户查询
                queryParam.setTaxAgents(Collections.singletonList(-1L));
            } else {
                queryParam.setTaxAgents(taxAgents);
            }
        }

        //补差列表
        queryParam.setPaymentStatus(PaymentStatusEnum.BALANCE.getValue());

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

        //系统人员核算明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统人员核算明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
        //数据组装
        List<Map<String, Object>> records = getService(user).buildCommonRecords(list, employeeId);
        Map<String, Object> sumRow = countSum(records);
        datas.put("sumRow", sumRow);
        return datas;
    }

    public Map<String, Object> countSum(List<Map<String, Object>> records ){
        // 获取需要统计的列
        String[] keys = {"Base", "Com", "Sum", "Per", "total"};
        Set<String> numKeys = new HashSet<>();
//        for(String key : maxSizeRecord.keySet()){
//            if(StringUtils.containsAny(key,keys)){
//                numKeys.add(key);
//            }
//        }
        for(int i =0; i < records.size(); i++){
            Map<String, Object> record = records.get(i);
            for(String key : record.keySet()){
                if(StringUtils.containsAny(key,keys)){
                    numKeys.add(key);
                }
            }
        }
        Map<String, Object> sumRow = new HashMap<>();
        for(String numKey : numKeys){
            BigDecimal value = new BigDecimal(0);
            for(Map<String, Object> record : records){
                BigDecimal addValue = null;
                if(record.get(numKey) == null || StringUtils.isBlank(record.get(numKey).toString())){
                    addValue = new BigDecimal(0);
                }else{
                    addValue = new BigDecimal(record.get(numKey).toString());
                }
                value = value.add(addValue);
            }
//            sumRow.put(numKey,value);
            sumRow.put(numKey,String.format("%.2f", value));

        }
        return sumRow;
    }


    /**
     * 检查补差数据中的福利缴纳费用相关福利类别，是否在正常缴纳中有设置缴纳
     * @param po
     * @return
     */
    @Override
    public boolean checkBalance(InsuranceAccountDetailPO po) {
        InsuranceAccountDetailPO commonAccountPO = getInsuranceAccountDetailMapper().getOneByBpep(InsuranceAccountDetailPO.builder()
                .billMonth(po.getBillMonth())
                .paymentStatus(PaymentStatusEnum.COMMON.getValue())
                .employeeId(po.getEmployeeId())
                .paymentOrganization(po.getPaymentOrganization())
                .build());
        if (commonAccountPO != null) {

            encryptUtil.decrypt(commonAccountPO, InsuranceAccountDetailPO.class);
            boolean commonSocialNullFlag = (StringUtils.isBlank(commonAccountPO.getSocialSum()) || SalaryEntityUtil.StringEqZERO(commonAccountPO.getSocialSum()));
            boolean commonFundNullFlag = (StringUtils.isBlank(commonAccountPO.getFundSum()) || SalaryEntityUtil.StringEqZERO(commonAccountPO.getFundSum()));
            boolean commonOtherNullFlag = (StringUtils.isBlank(commonAccountPO.getOtherSum()) || SalaryEntityUtil.StringEqZERO(commonAccountPO.getOtherSum()));

            boolean balanceSocialNullFlag = (StringUtils.isBlank(po.getSocialSum()) || SalaryEntityUtil.StringEqZERO(po.getSocialSum()));
            boolean balanceFundNullFlag = (StringUtils.isBlank(po.getFundSum()) || SalaryEntityUtil.StringEqZERO(po.getFundSum()));
            boolean balanceOtherNullFlag = (StringUtils.isBlank(po.getOtherSum()) || SalaryEntityUtil.StringEqZERO(po.getOtherSum()));
            //在正常缴纳数据中未设置的福利类别（社保、公积金、其他福利），不允许在补差数据中缴纳
            if ((commonSocialNullFlag && !balanceSocialNullFlag) || (commonFundNullFlag && !balanceFundNullFlag) || (commonOtherNullFlag && !balanceOtherNullFlag)) {
                return false;
            } else {
                return true;
            }
        } else {
            return false;
        }
    }

    /**
     * 检查补差数据中的福利缴纳费用相关福利项，是否在正常缴纳中方案所设置可缴纳
     * @param po
     * @return
     */
    @Override
    public boolean checkBalancePayInsurance(InsuranceAccountDetailPO po) {
        InsuranceAccountDetailPO commonAccountPO = getInsuranceAccountDetailMapper().getOneByBpep(InsuranceAccountDetailPO.builder()
                .billMonth(po.getBillMonth())
                .paymentStatus(PaymentStatusEnum.COMMON.getValue())
                .employeeId(po.getEmployeeId())
                .paymentOrganization(po.getPaymentOrganization())
                .build());
        if (commonAccountPO != null) {
            encryptUtil.decrypt(commonAccountPO, InsuranceAccountDetailPO.class);
            //判断社保缴纳福利项是否合规
            boolean socialPayFlag = true;
            Map<String, String> socialPerPayMap = JSON.parseObject(po.getSocialPerJson(), new HashMap<String, String>().getClass());
            Map<String, String> socialComPayMap = JSON.parseObject(po.getSocialComJson(), new HashMap<String, String>().getClass());
            //目标员工设置了方案时，比较方案中缴纳的福利项和补差中设置（有效值）的福利项
            if (commonAccountPO.getSocialSchemeId() != null) {
                List<String> payInsuranceIdAndScopeList = payInsuranceIdAndScopeList(commonAccountPO.getSocialSchemeId());
                if (socialPerPayMap != null) {
                    for (Map.Entry<String, String> entry : socialPerPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            socialPayFlag = false;
                            break;
                        }
                    }
                }

                if (socialPayFlag && socialComPayMap != null) {
                    for (Map.Entry<String, String> entry : socialComPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            socialPayFlag = false;
                            break;
                        }

                    }
                }

            } else {
                //目标员工未设置方案时，判断补差中是否设置（有效值）的福利项
                if (socialPerPayMap != null) {
                    for (Map.Entry<String, String> entry : socialPerPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            socialPayFlag = false;
                            break;
                        }

                    }
                }

                if (socialPayFlag && socialComPayMap != null) {
                    for (Map.Entry<String, String> entry : socialComPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            socialPayFlag = false;
                            break;
                        }

                    }
                }
            }

            //判断公积金缴纳福利项是否合规
            boolean fundPayFlag = true;
            Map<String, String> fundPerPayMap = JSON.parseObject(po.getFundPerJson(), new HashMap<String, String>().getClass());
            Map<String, String> fundComPayMap = JSON.parseObject(po.getFundComJson(), new HashMap<String, String>().getClass());
            //目标员工设置了方案时，比较方案中缴纳的福利项和补差中设置（有效值）的福利项
            if (commonAccountPO.getFundSchemeId() != null) {
                List<String> payInsuranceIdAndScopeList = payInsuranceIdAndScopeList(commonAccountPO.getFundSchemeId());
                if (fundPerPayMap != null) {
                    for (Map.Entry<String, String> entry : fundPerPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            fundPayFlag = false;
                            break;
                        }

                    }
                }

                if (fundPayFlag && fundComPayMap != null) {
                    for (Map.Entry<String, String> entry : fundComPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            fundPayFlag = false;
                            break;
                        }

                    }
                }

            } else {
                //目标员工未设置方案时，判断补差中是否设置（有效值）的福利项
                if (fundPerPayMap != null) {
                    for (Map.Entry<String, String> entry : fundPerPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            fundPayFlag = false;
                            break;
                        }

                    }
                }

                if (fundPayFlag && fundComPayMap != null) {
                    for (Map.Entry<String, String> entry : fundComPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            fundPayFlag = false;
                            break;
                        }

                    }
                }
            }

            //判断其他福利缴纳福利项是否合规
            boolean otherPayFlag = true;
            Map<String, String> otherPerPayMap = JSON.parseObject(po.getOtherPerJson(), new HashMap<String, String>().getClass());
            Map<String, String> otherComPayMap = JSON.parseObject(po.getOtherComJson(), new HashMap<String, String>().getClass());
            //目标员工设置了方案时，比较方案中缴纳的福利项和补差中设置（有效值）的福利项
            if (commonAccountPO.getOtherSchemeId() != null) {
                List<String> payInsuranceIdAndScopeList = payInsuranceIdAndScopeList(commonAccountPO.getOtherSchemeId());
                if (otherPerPayMap != null) {
                    for (Map.Entry<String, String> entry : otherPerPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            otherPayFlag = false;
                            break;
                        }

                    }
                }

                if (otherPayFlag && otherComPayMap != null) {
                    for (Map.Entry<String, String> entry : otherComPayMap.entrySet()) {
                        if (!payInsuranceIdAndScopeList.contains(entry.getKey() + "-" + PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                && StringUtils.isNotBlank(entry.getValue())) {
                            otherPayFlag = false;
                            break;
                        }

                    }
                }

            } else {
                //目标员工未设置方案时，判断补差中是否设置（有效值）的福利项
                if(otherPerPayMap != null) {
                    for (Map.Entry<String, String> entry : otherPerPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            otherPayFlag = false;
                            break;
                        }

                    }
                }
                if (otherPayFlag && otherComPayMap != null) {
                    for (Map.Entry<String, String> entry : otherComPayMap.entrySet()) {
                        if (StringUtils.isNotBlank(entry.getValue())) {
                            otherPayFlag = false;
                            break;
                        }

                    }
                }
            }

            //在社保、公积金、其他福利档案中未设置的福利项被补差设置有效数值时，不允许更新
            if (socialPayFlag && fundPayFlag && otherPayFlag) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    public List<String> payInsuranceIdAndScopeList(Long schemeId) {
        //查询该福利方案下开启缴纳的福利项
        List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(schemeId);
        List<String> insuranceIdList = new ArrayList<>();
        if (detailPOS != null && detailPOS.size() > 0) {
            //开启缴纳的
            insuranceIdList = detailPOS.stream().filter(f -> f.getIsPayment().equals(IsPaymentEnum.YES.getValue())).map(m -> {
                return m.getInsuranceId() .toString() + "-" + m.getPaymentScope().toString();
            }).collect(Collectors.toList());
        }
        return insuranceIdList;
    }

    public InsuranceAccountDetailPO buildBalanceAccountDetail(Long paymentOrganization, List<ICategoryPO> insuranceCategoryPOS,
                                                              List<Map<String, Object>> singleAccount, String billMonth, Long employeeId, Long creator) {
        InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
        insuranceAccountDetailPO.setId(IdGenerator.generate());
        insuranceAccountDetailPO.setEmployeeId(employeeId);
        insuranceAccountDetailPO.setBillMonth(billMonth.substring(0, 7));
        insuranceAccountDetailPO.setBillStatus(BillStatusEnum.NOT_ARCHIVED.getValue());
        insuranceAccountDetailPO.setPaymentStatus(PaymentStatusEnum.BALANCE.getValue());
        insuranceAccountDetailPO.setResourceFrom(ResourceFromEnum.IMPORT.getValue());

        insuranceAccountDetailPO.setCreator(creator);
        insuranceAccountDetailPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
        insuranceAccountDetailPO.setCreateTime(new Date());
        insuranceAccountDetailPO.setUpdateTime(new Date());
        insuranceAccountDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        insuranceAccountDetailPO.setPaymentOrganization(paymentOrganization);
        insuranceAccountDetailPO.setSocialPayOrg(paymentOrganization);
        insuranceAccountDetailPO.setFundPayOrg(paymentOrganization);
        insuranceAccountDetailPO.setOtherPayOrg(paymentOrganization);

        InsuranceArchivesBaseInfoPO baseInfoPO = getInsuranceBaseInfoMapper().getOneByEmployeeIdAndPayOrg(employeeId, paymentOrganization);
        if (baseInfoPO != null) {
            InsuranceArchivesSocialSchemePO socialSchemePO = getSocialSchemeMapper().getOneById(baseInfoPO.getSocialArchivesId());

            InsuranceArchivesFundSchemePO fundSchemePO = getFundSchemeMapper().getOneById(baseInfoPO.getFundArchivesId());
            if (socialSchemePO != null) {
                insuranceAccountDetailPO.setSocialAccount(socialSchemePO.getSocialAccount());
            }
            if (fundSchemePO != null) {
                insuranceAccountDetailPO.setFundAccount(fundSchemePO.getFundAccount());
                insuranceAccountDetailPO.setSupplementFundAccount(fundSchemePO.getSupplementFundAccount());
            }
        }

        //获取改员工社保档案
        accountBalanceSocial(singleAccount, insuranceAccountDetailPO, insuranceCategoryPOS, creator);
        accountBalanceFund(singleAccount, insuranceAccountDetailPO, insuranceCategoryPOS, creator);
        // 其他福利档案
        accountBalanceOther(singleAccount, insuranceAccountDetailPO, insuranceCategoryPOS, creator);
        account(insuranceAccountDetailPO);
        if (insuranceAccountDetailPO.getOtherSchemeId() == null) {
            insuranceAccountDetailPO.setOtherSchemeId(0L);
        }
        if (insuranceAccountDetailPO.getSocialSchemeId() == null) {
            insuranceAccountDetailPO.setSocialSchemeId(0L);
        }
        if (insuranceAccountDetailPO.getFundSchemeId() == null) {
            insuranceAccountDetailPO.setFundSchemeId(0L);
        }
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountBalanceSocial(List<Map<String, Object>> singleAccount, InsuranceAccountDetailPO insuranceAccountDetailPO,
                                                         List<ICategoryPO> insuranceCategoryPOS, Long employeeId) {
        //社保-个人
        List<ICategoryPO> socialCategory = insuranceCategoryPOS.stream().filter(po -> po.getWelfareType().equals(WelfareTypeEnum.SOCIAL_SECURITY.getValue()))
                .collect(Collectors.toList());
        List<BigDecimal> socialPer = new ArrayList<>();
        Map<String, String> socialPerJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = socialCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"));
                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }

                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                socialPerJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                socialPer.add(result);
            }
        }
        insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
        BigDecimal socialPerSum = new BigDecimal("0");
        for (BigDecimal bigDecimal : socialPer) {
            socialPerSum = socialPerSum.add(bigDecimal);
        }
        insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());

        //社保-单位
        List<BigDecimal> socialCom = new ArrayList<>();
        Map<String, String> sociaComJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = socialCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"));

                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }
                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                sociaComJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                socialCom.add(result);
            }
        }
        insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
        BigDecimal socialComSum = new BigDecimal("0");
        for (BigDecimal decimal : socialCom) {
            socialComSum = socialComSum.add(decimal);
        }
        insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountBalanceFund(List<Map<String, Object>> singleAccount, InsuranceAccountDetailPO insuranceAccountDetailPO,
                                                       List<ICategoryPO> insuranceCategoryPOS, Long employeeId) {
        //公积金-个人
        List<ICategoryPO> fundCategory = insuranceCategoryPOS.stream().filter(po -> po.getWelfareType().equals(WelfareTypeEnum.ACCUMULATION_FUND.getValue()))
                .collect(Collectors.toList());
        List<BigDecimal> fundPer = new ArrayList<>();
        Map<String, String> fundPerJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = fundCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"));
                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }
                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                fundPerJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                fundPer.add(result);
            }
        }
        insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerJsonMap));
        BigDecimal funPerSum = new BigDecimal("0");
        for (BigDecimal bigDecimal : fundPer) {
            funPerSum = funPerSum.add(bigDecimal);
        }
        insuranceAccountDetailPO.setFundPerSum(funPerSum.toPlainString());

        //公积金-单位
        List<BigDecimal> fundComList = new ArrayList<>();
        Map<String, String> fundComJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = fundCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"));
                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }
                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                fundComJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                fundComList.add(result);
            }
        }
        insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComJsonMap));
        BigDecimal fundComSum = new BigDecimal("0");
        for (BigDecimal bigDecimal : fundComList) {
            fundComSum = fundComSum.add(bigDecimal);
        }
        insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());
        return insuranceAccountDetailPO;
    }

    public InsuranceAccountDetailPO accountBalanceOther(List<Map<String, Object>> singleAccount, InsuranceAccountDetailPO insuranceAccountDetailPO,
                                                        List<ICategoryPO> insuranceCategoryPOS, Long employeeId) {
        List<ICategoryPO> otherCategory = insuranceCategoryPOS.stream().filter(po -> po.getWelfareType().equals(WelfareTypeEnum.OTHER.getValue()))
                .collect(Collectors.toList());
        // 其他福利-个人
        List<BigDecimal> otherPer = new ArrayList<>();
        Map<String, String> otherPerJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = otherCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(87159, "个人"));
                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }
                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                otherPerJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                otherPer.add(result);
            }
        }
        insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerJsonMap));
        BigDecimal otherPerSum = new BigDecimal("0");
        for (BigDecimal bigDecimal : otherPer) {
            otherPerSum = otherPerSum.add(bigDecimal);
        }
        insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());

        // 其他福利-单位
        List<BigDecimal> otherComList = new ArrayList<>();
        Map<String, String> otherComJsonMap = new HashMap<>();
        for (int i = 0; i < singleAccount.size(); i++) {
            Map<String, Object> stringObjectMap = singleAccount.get(i);
            Optional<ICategoryPO> personalOptional = otherCategory.stream()
                    .filter(social -> stringObjectMap.containsKey(social.getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"))).findFirst();
            if (personalOptional.isPresent() && StringUtils
                    .isNotBlank((String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位")))) {
                String perNumString = (String) stringObjectMap.get(personalOptional.get().getInsuranceName() + SalaryI18nUtil.getI18nLabel(100289, "单位"));
                if (perNumString.length() > 0 && !isNumeric(perNumString)) {
                    continue;
                }
                perNumString = perNumString.replace(",", "");
                BigDecimal result = new BigDecimal(perNumString);
                otherComJsonMap.put(String.valueOf(personalOptional.get().getId()), result.toPlainString());
                otherComList.add(result);
            }
        }
        insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComJsonMap));
        BigDecimal otherComSum = new BigDecimal("0");
        for (BigDecimal bigDecimal : otherComList) {
            otherComSum = otherComSum.add(bigDecimal);
        }
        insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
        return insuranceAccountDetailPO;
    }
    /*****以下代码为SIAccountBiz中逻辑迁移，旨在减少Biz类的使用*****/

    /**
     * 新建核算并归档
     * @param param
     * @return
     */
    @Override
    public String saveAndFile(AccountParam param) {
        ValidUtil.doValidator(param);
        if (param.isFlag()) {
            InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
            insuranceAccountBatchPO = encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
            SalaryAssert.isNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(0, "所属月份存在核算数据"));

            InsuranceAccountBatchPO build = InsuranceAccountBatchPO.builder()
                    .paymentOrganization(param.getPaymentOrganization())
                    .accountant(user.getLastname())
                    .billMonth(param.getBillMonth())
                    .billStatus(BillStatusEnum.NOT_ARCHIVED.getValue())
                    .remarks(param.getRemarks())
                    .creator((long) user.getUID())
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .createTime(new Date())
                    .updateTime(new Date())
                    .deleteType(DeleteTypeEnum.NOT_DELETED.getValue())
                    .paymentOrganization(param.getPaymentOrganization())
                    .socialPay("0")
                    .fundPay("0")
                    .otherPay("0")
                    .build();
            encryptUtil.encrypt(build, InsuranceAccountBatchPO.class);
            getInsuranceAccountBatchMapper().insert(build);
            //记录操作日志
            InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
            encryptUtil.decrypt(targetPO, InsuranceAccountBatchPO.class);
            TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
            LoggerContext<InsuranceAccountBatchPO> loggerContext = new LoggerContext();
            loggerContext.setUser(user);
            loggerContext.setTargetId(String.valueOf(targetPO.getId()));
            loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
            loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新增福利台账"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新增福利台账")
                    + ":" + taxAgentInfo.getName() + "-" + targetPO.getBillMonth());
            loggerContext.setNewValues(targetPO);
            SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
        }
        try {
            List<Long> employeeIds = getInsuranceAccountDetailMapper().selectEmpByPaymentOrg(param.getPaymentOrganization());
            if (CollectionUtils.isEmpty(employeeIds)) {
                List<InsuranceAccountDetailPO> list = Lists.newArrayList(getInsuranceAccountDetailMapper().queryNormalListByBillMonth(param.getBillMonth(), param.getPaymentOrganization()));
                encryptUtil.decryptList(list, InsuranceAccountDetailPO.class);
                if (CollectionUtils.isNotEmpty(list)) {
                    list.stream().forEach(f -> {
                        getInsuranceAccountDetailMapper().deleteById(f.getId());
                    });
                }
            }
            SalaryAssert.notEmpty(employeeIds, SalaryI18nUtil.getI18nLabel(0, "没有需要核算的人员"));
//            AccountParam selectParam = new AccountParam();
//            selectParam.setBillMonth(param.getBillMonth());
//            selectParam.setPaymentOrganization(param.getPaymentOrganization());
            ExecutorService taskExecutor = Executors.newCachedThreadPool();
            taskExecutor.execute(() -> {
                siAccounting(param);
                if (param.isFileFlag()) {
                    siFile(param.getBillMonth(), param.getPaymentOrganization());
                }
            });
        } catch (Exception e) {
            // 回滚
            List<InsuranceAccountBatchPO> list = Lists.newArrayList(getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization()));
            list = encryptUtil.decryptList(list, InsuranceAccountBatchPO.class);
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(f -> {
                    getInsuranceAccountBatchMapper().deleteById(f.getId());
                });
            }
            throw new SalaryRunTimeException(e.getMessage());
        }
        return String.valueOf(user.getUID());
    }


    public void siAccounting(AccountParam param) {
        //福利核算进度
        ProgressDTO salaryAcctProgressDTO = getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth());
        if (salaryAcctProgressDTO != null && salaryAcctProgressDTO.isStatus() && salaryAcctProgressDTO.getProgress().compareTo(BigDecimal.ONE) < 0) {
            return;
        }

        log.info("开始核算，当前操作人为:{}", user.getLastname());
        log.info("核算时间:{}, 核算月份:{}, 个税扣缴义务人:{}, 是否首次核算:{}", new Date(), param.getBillMonth(), param.getPaymentOrganization(), param.isFlag());
        try {
            List<Long> ids;
            List<Long> validIds = new ArrayList<>();
            if (CollectionUtils.isEmpty(param.getIds())) {
                List<Long> empIds = getInsuranceAccountDetailMapper().selectEmpByPaymentOrg(param.getPaymentOrganization());
                // 获取薪资核算人员规则
                SalarySysConfPO salaryAcctEmployeeRule = getSalarySysConfService(user).getOneByCode(SalarySysConstant.SALARY_ACCT_EMPLOYEE_RULE);
                List<String> status = new ArrayList<>();
                if(Objects.isNull(salaryAcctEmployeeRule) || StringUtils.equals(salaryAcctEmployeeRule.getConfValue(), SalaryAcctEmployeeRuleEnum.BYPAYENDTIME.getValue()) ){
                    // 包含停缴
                    status = Arrays.asList(EmployeeStatusEnum.PAYING.getValue(),EmployeeStatusEnum.STAY_DEL.getValue(),
                            EmployeeStatusEnum.STOP_PAYMENT_FROM_DEL.getValue());
                }else{
                    status = Arrays.asList(EmployeeStatusEnum.PAYING.getValue(),EmployeeStatusEnum.STAY_DEL.getValue());
                }
                List<String> finalStatus = status;
                //过滤出需要核算的人员，即福利档案基础信息表中runStatus为正在缴纳和待减员的人员
                List<InsuranceArchivesBaseInfoPO> baseInfoPOList = getInsuranceBaseInfoMapper().listAll();
                List<Long> canAccountIds = baseInfoPOList.stream()
                        .filter(f->f.getPaymentOrganization().equals(param.getPaymentOrganization())
                                && (finalStatus.contains(f.getRunStatus()) ))
                        .map(InsuranceArchivesBaseInfoPO::getEmployeeId)
                        .collect(Collectors.toList());

                //20231122逻辑优化，过滤出不在起始缴纳月和最后缴纳月区间的人员
                List<Long> empIdsInPayMonthRange = listCanPayEmpIds(param.getPaymentOrganization(), param.getBillMonth());
                empIds = empIds.stream().filter(f->canAccountIds.contains(f) && empIdsInPayMonthRange.contains(f)).collect(Collectors.toList());

//                List<InsuranceArchivesSocialSchemePO> socials = siArchivesBiz.getSocialByEmployeeIds(empIds);
                List<InsuranceArchivesSocialSchemePO> socials = getSIArchivesService(user).getSocialByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                socials = socials.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp1 = socials.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getSocialEndTime()) && StringUtils.isBlank(s.getSocialStartTime())) &&
                                (StringUtils.isBlank(s.getSocialEndTime()) || (SalaryDateUtil.stringToDate(s.getSocialEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getSocialEndTime() + "-01")))) )
                        .map(InsuranceArchivesSocialSchemePO::getEmployeeId)
                        .collect(Collectors.toList());

//                List<InsuranceArchivesFundSchemePO> funds = siArchivesBiz.getFundByEmployeeIds(empIds);
                List<InsuranceArchivesFundSchemePO> funds = getSIArchivesService(user).getFundByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                funds = funds.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp2 = funds.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getFundStartTime()) && StringUtils.isBlank(s.getFundEndTime())) &&
                                (StringUtils.isBlank(s.getFundEndTime()) || (SalaryDateUtil.stringToDate(s.getFundEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getFundEndTime() + "-01")))))
                        .map(InsuranceArchivesFundSchemePO::getEmployeeId)
                        .collect(Collectors.toList());

//                List<InsuranceArchivesOtherSchemePO> others = siArchivesBiz.getOtherByEmployeeIds(empIds);
                List<InsuranceArchivesOtherSchemePO> others = getSIArchivesService(user).getOtherByEmployeeIds(empIds);
                //过滤出目标个税扣缴义务人相关信息
                others = others.stream().filter(f -> f.getPaymentOrganization().equals(param.getPaymentOrganization())).collect(Collectors.toList());
                List<Long> emp3 = others.stream()
                        .filter(s -> !(StringUtils.isBlank(s.getOtherStartTime()) && StringUtils.isBlank(s.getOtherEndTime())) &&
                                (StringUtils.isBlank(s.getOtherEndTime()) || (SalaryDateUtil.stringToDate(s.getOtherEndTime() + "-01") != null && !SalaryDateUtil.stringToDate(param.getBillMonth() + "-01").after(SalaryDateUtil.stringToDate(s.getOtherEndTime() + "-01")))))
                        .map(InsuranceArchivesOtherSchemePO::getEmployeeId)
                        .collect(Collectors.toList());
                validIds.addAll(emp1);
                validIds.addAll(emp2);
                validIds.addAll(emp3);

                List<Long> finalValidIds = validIds.stream().distinct().collect(Collectors.toList());
                ids = empIds.stream().filter(finalValidIds::contains).collect(Collectors.toList());
            } else {
                ids = param.getIds();
            }

            // 初始化进度
            ProgressDTO initProgress = new ProgressDTO()
                    .setTitle(SalaryI18nUtil.getI18nLabel(0, "核算中"))
                    .setTitleLabelId(97515L)
                    .setTotalQuantity(ids.size())
                    .setCalculatedQuantity(NumberUtils.INTEGER_ZERO)
                    .setProgress(BigDecimal.ZERO)
                    .setStatus(true)
                    .setMessage(StringUtils.EMPTY);
            getSalaryAcctProgressService(user).initProgress(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), initProgress);

            if (CollectionUtils.isEmpty(ids)) {
                getSalaryAcctProgressService(user).finish(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), true);
                return;
            }

            log.info("开始生成福利核算数据，待处理人员数量:{}", ids.size());
            siCommonAccount(param.getBillMonth(), ids, param.getPaymentOrganization());
            log.info("福利核算数据生成完毕，开始数据处理");

            handleData(ids, param);
            log.info("福利核算数据处理完毕！");

            List<List<Long>> partition = Lists.partition((List<Long>) ids, 100);
            partition.forEach(part -> {
                getSIAccountDetailTempMapper().batchDelByEmpIdsAndMonthAndPayOrg(part, param.getBillMonth(), param.getPaymentOrganization());
            });
            log.info("更新福利核算进度······");
            getSalaryAcctProgressService(user).finish(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), true);
            log.info("福利核算进度完成！");
        } catch (Exception e) {
            log.error("account run fail", e);
            getSalaryAcctProgressService(user).fail(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), SalaryI18nUtil.getI18nLabel(0, "福利核算出错") + ": " + e.getMessage());

            List<InsuranceAccountBatchPO> list = Lists.newArrayList(getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization()));
            if (CollectionUtils.isNotEmpty(list)) {
                list.stream().forEach(f -> {
                    getInsuranceAccountBatchMapper().deleteById(f.getId());
                });
            }

        }

    }

    public void siCommonAccount(String billMonth, List<Long> ids, Long paymentOrganization) {

//        Map<Long, InsuranceArchivesAccountPO> insuranceArchivesAccountPOS = siArchivesBiz.buildBatchAccount(ids, paymentOrganization);
        Map<Long, InsuranceArchivesAccountPO> insuranceArchivesAccountPOS = getSIArchivesService(user).buildBatchAccount(ids, paymentOrganization);
        List<InsuranceAccountDetailTempPO> list = new ArrayList<>();
        int count = 0;
        for (Map.Entry<Long, InsuranceArchivesAccountPO> entry : insuranceArchivesAccountPOS.entrySet()) {
            Long k = entry.getKey();
            InsuranceArchivesAccountPO v = entry.getValue();
            InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
            insuranceAccountDetailPO.setBillMonth(billMonth);
            insuranceAccountDetailPO.setBillStatus(BillStatusEnum.NOT_ARCHIVED.getValue());
            insuranceAccountDetailPO.setCreator((long) user.getUID());
            insuranceAccountDetailPO.setCreateTime(new Date());
            insuranceAccountDetailPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
            insuranceAccountDetailPO.setEmployeeId(k);
            insuranceAccountDetailPO.setUpdateTime(new Date());
            insuranceAccountDetailPO.setPaymentStatus(PaymentStatusEnum.COMMON.getValue());
            insuranceAccountDetailPO.setResourceFrom(ResourceFromEnum.SYSTEM.getValue());
            insuranceAccountDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
            insuranceAccountDetailPO.setPaymentOrganization(paymentOrganization);

            //核算社保
            accountSocial(insuranceAccountDetailPO, v, billMonth);
            //核算公积金
            accountFund(insuranceAccountDetailPO, v, billMonth);
            //核算其他福利
            accountOther(insuranceAccountDetailPO, v, billMonth);
            //计算合计
            account(insuranceAccountDetailPO);
            //临时表PO
            InsuranceAccountDetailTempPO insuranceAccountDetailTempPO = new InsuranceAccountDetailTempPO();
            BeanUtils.copyProperties(insuranceAccountDetailPO, insuranceAccountDetailTempPO);
            list.add(insuranceAccountDetailTempPO);
            count++;

            if (count % 50 == 0 || count >= ids.size()) {
                if (count >= ids.size()) {
                    getSalaryAcctProgressService(user).updateProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth, BigDecimal.valueOf(0.99), false);
                    log.info("更新福利核算进度，当前进度为:{}", getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth));
                } else {
                    getSalaryAcctProgressService(user).getAndAddCalculatedQty(SalaryCacheKey.ACCT_PROGRESS + billMonth, count >= ids.size() ? count % 50 : 50);
                    log.info("更新福利核算进度，当前进度为:{}", getSalaryAcctProgressService(user).getProgress(SalaryCacheKey.ACCT_PROGRESS + billMonth));
                }

            }

        }
        //临时表入库前先对（可能存在的）历史数据进行删除
        List<List<Long>> partition = Lists.partition((List<Long>) ids, 100);
        partition.forEach(part -> {
            getSIAccountDetailTempMapper().batchDelByEmpIdsAndMonthAndPayOrg(part, billMonth, paymentOrganization);
        });
        //临时表数据入库
        if (CollectionUtils.isNotEmpty(list)) {
            encryptUtil.encryptList(list, InsuranceAccountDetailTempPO.class);
            List<List<InsuranceAccountDetailTempPO>> lists = splitList(list, 40);
            lists.forEach(subList -> {
                getSIAccountDetailTempMapper().batchSaveAccountTempDetails(subList);
            });
        }

    }

    public InsuranceAccountDetailPO accountOther(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();
        if (accountPO.getOther() != null) {
            InsuranceArchivesOtherSchemePO otherPO = accountPO.getOther();
            insuranceAccountDetailPO.setOtherPayOrg(otherPO.getPaymentOrganization());
            insuranceAccountDetailPO.setOtherSchemeId(otherPO.getOtherSchemeId());
            insuranceAccountDetailPO.setOtherPaymentBaseString(otherPO.getOtherPaymentBaseString());
            insuranceAccountDetailPO.setOtherPaymentComBaseString(otherPO.getOtherPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), otherPO.getOtherStartTime(), otherPO.getOtherEndTime());
            if ((Objects.equals(NonPaymentEnum.YES.getValue(), otherPO.getNonPayment()) || otherPO.getNonPayment() == null) && otherPO.getOtherSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(otherPO.getOtherSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳其他的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> otherPerson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算其他的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (otherPerson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(otherPerson.size() > 0) {
                    otherPerson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherPerson, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherPer = new ArrayList<>();
                Map<String, String> otherPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherPerson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (po.getPaymentCycle() != null && po.getPaymentCycle() == 1) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    otherPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherPer.add(result);
                });
                insuranceAccountDetailPO.setOtherPerJson(JSON.toJSONString(otherPerJsonMap));
                BigDecimal otherPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherPer) {
                    otherPerSum = otherPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> otherCom = detailPOS.stream()
                        .filter(
                                item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                        && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(otherPO.getOtherPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算其他的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (otherCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(otherCom.size() > 0) {
                    otherCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(otherCom, billMonth, otherPO.getOtherStartTime());

                List<BigDecimal> otherComList = new ArrayList<>();
                Map<String, String> otherComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = otherCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    otherComJsonMap.put(String.valueOf(e), result.toPlainString());
                    otherComList.add(result);
                });
                insuranceAccountDetailPO.setOtherComJson(JSON.toJSONString(otherComJsonMap));
                BigDecimal otherComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : otherComList) {
                    otherComSum = otherComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }


    public InsuranceAccountDetailPO accountFund(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();
        if (accountPO.getFund() != null) {
            InsuranceArchivesFundSchemePO fundPO = accountPO.getFund();
            insuranceAccountDetailPO.setFundPayOrg(fundPO.getPaymentOrganization());
            insuranceAccountDetailPO.setFundAccount(fundPO.getFundAccount());
            insuranceAccountDetailPO.setSupplementFundAccount(fundPO.getSupplementFundAccount());
            insuranceAccountDetailPO.setFundSchemeId(fundPO.getFundSchemeId());
            insuranceAccountDetailPO.setFundPaymentBaseString(fundPO.getFundPaymentBaseString());
            insuranceAccountDetailPO.setFundPaymentComBaseString(fundPO.getFundPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), fundPO.getFundStartTime(), fundPO.getFundEndTime());
            if ((NonPaymentEnum.YES.getValue().equals(fundPO.getNonPayment()) || fundPO.getNonPayment() == null) && fundPO.getFundSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(fundPO.getFundSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> fundperson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算公积金的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (fundperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(fundperson.size() > 0) {
                    fundperson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundperson, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundPer = new ArrayList<>();
                Map<String, String> fundPerJsonMap = new HashMap<>();
                needArchivesPerson.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    fundPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundPer.add(result);
                });
                insuranceAccountDetailPO.setFundPerJson(JSON.toJSONString(fundPerJsonMap));
                BigDecimal funPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundPer) {
                    funPerSum = funPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundPerSum(funPerSum.toPlainString());

                //方案中包含的需要缴纳公积金的单位福利
                Map<Long, InsuranceSchemeDetailPO> fundCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(fundPO.getFundPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算公积金的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (fundCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(fundCom.size() > 0) {
                    fundCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(fundCom, billMonth, fundPO.getFundStartTime());

                List<BigDecimal> fundComList = new ArrayList<>();
                Map<String, String> fundComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = fundCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    fundComJsonMap.put(String.valueOf(e), result.toPlainString());
                    fundComList.add(result);
                });
                insuranceAccountDetailPO.setFundComJson(JSON.toJSONString(fundComJsonMap));
                BigDecimal fundComSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : fundComList) {
                    fundComSum = fundComSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }


    public InsuranceAccountDetailPO accountSocial(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, String billMonth) {
//        boolean welBaseDiffSign = siArchivesBiz.isDiffWelBase();
        boolean welBaseDiffSign = getSIArchivesService(user).isDiffWelBase();
        if (accountPO.getSocial() != null) {
            InsuranceArchivesSocialSchemePO socialPO = accountPO.getSocial();
            insuranceAccountDetailPO.setSocialPayOrg(socialPO.getPaymentOrganization());
            insuranceAccountDetailPO.setSocialAccount(socialPO.getSocialAccount());
            insuranceAccountDetailPO.setSocialSchemeId(socialPO.getSocialSchemeId());
            insuranceAccountDetailPO.setSocialPaymentBaseString(socialPO.getSocialPaymentBaseString());
            insuranceAccountDetailPO.setSocialPaymentComBaseString(socialPO.getSocialPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(insuranceAccountDetailPO.getBillMonth(), socialPO.getSocialStartTime(), socialPO.getSocialEndTime());
            if ((NonPaymentEnum.YES.getValue().equals(socialPO.getNonPayment()) || socialPO.getNonPayment() == null) && socialPO.getSocialSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(socialPO.getSocialSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> schemeperson = detailPOS.stream()
                        .filter(item ->
                                Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) &&
                                        Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue()) &&
                                        (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1")))
                        )
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    archivesPerson.forEach((id, value) -> {
                        if (schemeperson.containsKey(Long.valueOf(id))) {
                            needArchivesPerson.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(schemeperson.size() > 0) {
                    schemeperson.forEach((id, object) -> {
                        if (!needArchivesPerson.contains(id)) {
                            needArchivesPerson.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeperson, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialPer = new ArrayList<>();
                Map<String, String> socialPerJsonMap = new HashMap<>();
                needArchivesPerson.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    socialPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialPer.add(result);
                });
                insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
                BigDecimal socialPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : socialPer) {
                    socialPerSum = socialPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
                //方案中包含的需要缴纳社保的单位福利
                Map<Long, InsuranceSchemeDetailPO> schemeCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) &&
                                (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesCom = new HashMap<>();
                if (welBaseDiffSign) {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentComBaseString(), new HashMap<String, String>().getClass());
                } else {
                    archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                }
                //需要核算社保的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    archivesCom.forEach((id, value) -> {
                        if (schemeCom.containsKey(Long.valueOf(id))) {
                            needArchivesCom.add(Long.valueOf(id));
                        }
                    });
                }
                //避免福利档案的方案未设置基数，导致核算时遗漏这些福利项的核算，遍历下方案相关福利项，并将遗漏的福利项id添加
                if(schemeCom.size() > 0) {
                    schemeCom.forEach((id, object) -> {
                        if (!needArchivesCom.contains(id)) {
                            needArchivesCom.add(id);
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeCom, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialCom = new ArrayList<>();
                Map<String, String> sociaComJsonMap = new HashMap<>();
                HashMap<String, String> finalArchivesCom = archivesCom;
                needArchivesCom.stream().forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(StringUtils.isBlank(po.getPaymentProportion()) ? "0" : po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(finalArchivesCom) || StringUtils.isBlank(finalArchivesCom.get(String.valueOf(e)))) ? "0" : finalArchivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    sociaComJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialCom.add(result);

                });
                insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
                BigDecimal socialComSum = new BigDecimal("0");
                for (BigDecimal decimal : socialCom) {
                    socialComSum = socialComSum.add(decimal);
                }
                insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
            }

        }
        return insuranceAccountDetailPO;
    }

    /**
     * 对于核算月和福利起始缴纳月处于同年时，要避免根据周期缴纳福利费用时，可能出现的多余费用缴纳情况
     * @param schemeDetail 福利方案明细
     * @param billMonth 核算月
     * @param startMonth 福利起始缴纳月
     * @return
     */
    public Map<Long, InsuranceSchemeDetailPO> checkCycleSettingWithStartMonth(Map<Long, InsuranceSchemeDetailPO> schemeDetail, String billMonth, String startMonth) {
        String billYear = billMonth.substring(0,4);
        if (StringUtils.isNotBlank(startMonth) && billYear.equals(startMonth.substring(0,4))) {
            int startMonthIndex = Integer.parseInt(startMonth.split("-")[1]) - 1;
            schemeDetail.forEach((k, v) -> {
                if (v.getPaymentCycle() != null && v.getPaymentCycle().equals(1) && startMonthIndex != 0) {
                    StringBuilder newCycleSetting = new StringBuilder(v.getCycleSetting());
                    newCycleSetting.setCharAt(startMonthIndex - 1, '1');
                    v.setCycleSetting(newCycleSetting.toString());
                }
            });

        }
        return schemeDetail;
    }

    private List<List<InsuranceAccountDetailTempPO>> splitList(List<InsuranceAccountDetailTempPO> list, int groupSize) {
        int length = list.size();
        // 计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        List<List<InsuranceAccountDetailTempPO>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            newList.add(list.subList(fromIndex, toIndex));
        }
        return newList;
    }

    /**
     * 根据个税扣缴义务人和账单月，获取三类福利档案中符合缴纳开始结束月区间的人员id
     * @param paymentOrganization
     * @param billMonth
     * @return
     */
    public List<Long> listCanPayEmpIds(Long paymentOrganization, String billMonth) {
        List<Long> listCanPayEmpIds = new ArrayList<>();
        //社保档案中可进行缴纳的人员
        List<Long> socialCanPayEmpIds = getSocialSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth);
        //公积金档案中可进行缴纳的人员
        List<Long> fundCanPayEmpIds = getFundSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth);
        //其他福利档案中可进行缴纳的人员
        List<Long> otherCanPayEmpIds = getOtherSchemeMapper().listCanPayEmpIds(paymentOrganization, billMonth);
        if (socialCanPayEmpIds != null && socialCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(socialCanPayEmpIds);
        }
        if (fundCanPayEmpIds != null && fundCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(fundCanPayEmpIds);
        }
        if (otherCanPayEmpIds != null && otherCanPayEmpIds.size() > 0) {
            listCanPayEmpIds.addAll(otherCanPayEmpIds);
        }
        //去重
        listCanPayEmpIds = listCanPayEmpIds.stream().distinct().collect(Collectors.toList());
        return listCanPayEmpIds;
    }

    private void handleData(List<Long> ids, AccountParam param) {
        String billMonth = param.getBillMonth();
        try {
            List<InsuranceAccountDetailTempPO> list = new ArrayList<>();
            List<List<Long>> partitionDetailTempInfo = Lists.partition((List<Long>) ids, 100);
            partitionDetailTempInfo.forEach(part -> list.addAll(
                    getSIAccountDetailTempMapper().getListByEmployeeIdsAndBillMonth(part, billMonth, param.getPaymentOrganization())));

            encryptUtil.decryptList(list, InsuranceAccountDetailTempPO.class);
            Integer paymentStatus = 0;
            log.info("核算明细临时表 hrsa_bill_detail_temp待处理数量：{}", list.size());
            List<List<Long>> partitionIds = Lists.partition((List<Long>) ids, 100);
            log.info("bill_detail入库前删除数据数量：{}", ids.size());
            for (List<Long> part : partitionIds) {
                getInsuranceAccountDetailMapper().batchDelAccountDetails(part, billMonth, param.getPaymentOrganization(), paymentStatus);

                //删除账单月份+个税扣缴义务人+人员id下的调差数据
                getInsuranceCompensationMapper().deleteByBillMonthPayOrgEmpIds(InsuranceCompensationPO.builder()
                        .billMonth(billMonth)
                        .paymentOrganization(param.getPaymentOrganization())
                        .employeeIds(part)
                        .build());
            }

            //生成bill_detail入库数据
            List<InsuranceAccountDetailPO> collect = list.stream().map(item -> {
                InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
                BeanUtils.copyProperties(item, insuranceAccountDetailPO);
                return insuranceAccountDetailPO;
            }).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)) {
                log.info("bill_detail入库数据数量：{}", collect.size());
                batchSaveAccountInspectDetail(collect);
                encryptUtil.encryptList(collect, InsuranceAccountDetailPO.class);
                List<List<InsuranceAccountDetailPO>> lists = splitDetailList(collect, 20);
                lists.forEach(subList -> {
                    getInsuranceAccountDetailMapper().batchSaveAccountDetails(subList);
                });
                updateBatchAccount(param);
            }
        } catch (Exception e) {
            log.error("福利核算数据处理失败", e);
            getSalaryAcctProgressService(user).fail(SalaryCacheKey.ACCT_PROGRESS + param.getBillMonth(), SalaryI18nUtil.getI18nLabel(0, "福利核算出错") + ": " + e.getMessage());
            throw e;
        }
    }

    public void batchSaveAccountInspectDetail(List<InsuranceAccountDetailPO> list) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectAllPOS = accountInspect(list, true);
        batchDelInspectDetail(insuranceAccountInspectAllPOS);
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = accountInspect(list, false);
        if (CollectionUtils.isNotEmpty(insuranceAccountInspectPOS)) {
            batchSaveInspectDetail(insuranceAccountInspectPOS);
        }
    }
    public void batchDelInspectDetail(List<InsuranceAccountInspectPO> list) {
        List<List<InsuranceAccountInspectPO>> lists = Lists.partition(list, 100);
        lists.forEach(getInsuranceAccountInspectMapper()::batchDelInspectDetails);

    }

    public void batchSaveInspectDetail(List<InsuranceAccountInspectPO> list) {
        List<List<InsuranceAccountInspectPO>> lists = Lists.partition(list, 100);
        lists.forEach(getInsuranceAccountInspectMapper()::batchSaveInspectDetails);
    }

    public List<InsuranceAccountInspectPO> accountInspect(List<InsuranceAccountDetailPO> list, boolean isAll) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = new ArrayList<>();
        for (InsuranceAccountDetailPO e : list) {
            if (isAll || detailCheck(e.getSocialPerJson()) || detailCheck(e.getSocialComJson())
                    || detailCheck(e.getFundPerJson()) || detailCheck(e.getFundComJson())
                    || detailCheck(e.getOtherPerJson()) || detailCheck(e.getOtherComJson())) {
                InsuranceAccountInspectPO insuranceAccountInspectPO = InsuranceAccountInspectPO.builder().build();
                insuranceAccountInspectPO.setSupplementaryProjects(e.getSupplementaryProjects());
                insuranceAccountInspectPO.setInspectStatus(InspectStatusEnum.IGNORE.getValue());
                insuranceAccountInspectPO.setBillMonth(e.getBillMonth());
                insuranceAccountInspectPO.setCreator(e.getCreator());
                insuranceAccountInspectPO.setCreateTime(new Date());
                insuranceAccountInspectPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
                insuranceAccountInspectPO.setEmployeeId(e.getEmployeeId());
                insuranceAccountInspectPO.setPaymentStatus(e.getPaymentStatus());
                insuranceAccountInspectPO.setSupplementaryMonth(e.getSupplementaryMonth());
                insuranceAccountInspectPO.setTenantKey(e.getTenantKey());
                insuranceAccountInspectPO.setUpdateTime(new Date());
                insuranceAccountInspectPOS.add(insuranceAccountInspectPO);
            }
        }
        return insuranceAccountInspectPOS;
    }

    public boolean detailCheck(String baseString) {
        if (StringUtils.isEmpty(baseString)) {
            return false;
        }
        Map<String, String> baseStringMap = JSON.parseObject(baseString, new TypeReference<Map<String, String>>() {
        });
        if (baseStringMap == null || baseStringMap.size() == 0) {
            return false;
        }
        return baseStringMap.values().stream().anyMatch(item -> StringUtils.isEmpty(item) || Pattern.matches("^([0].?[0]*)$", item));

    }

    private List<List<InsuranceAccountDetailPO>> splitDetailList(List<InsuranceAccountDetailPO> list, int groupSize) {
        int length = list.size();
        // 计算可以分成多少组
        int num = (length + groupSize - 1) / groupSize;
        List<List<InsuranceAccountDetailPO>> newList = new ArrayList<>(num);
        for (int i = 0; i < num; i++) {
            // 开始位置
            int fromIndex = i * groupSize;
            // 结束位置
            int toIndex = (i + 1) * groupSize < length ? (i + 1) * groupSize : length;
            newList.add(list.subList(fromIndex, toIndex));
        }
        return newList;
    }

    /**
     * 更新台账接口
     */
    public void updateBatchAccount(AccountParam param) {
        String billMonth = param.getBillMonth();

        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().selectList(billMonth, param.getPaymentOrganization());
        Map<Long, List<InsuranceAccountDetailPO>> map = insuranceAccountDetailPOS.stream().filter(item -> item.getEmployeeId() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getEmployeeId));
        int socialAccountPerson = 0;
        int funcAccountPerson = 0;
        int otherAccountPerson = 0;
        BigDecimal socialSum = new BigDecimal("0");
        BigDecimal fundSum = new BigDecimal("0");
        BigDecimal otherSum = new BigDecimal("0");
        for (Map.Entry<Long, List<InsuranceAccountDetailPO>> entry : map.entrySet()) {
            List<InsuranceAccountDetailPO> v = entry.getValue();
            BigDecimal socialTemp = new BigDecimal("0");
            BigDecimal fundTemp = new BigDecimal("0");
            BigDecimal otherTemp = new BigDecimal("0");
            encryptUtil.decryptList(v, InsuranceAccountDetailPO.class);
            boolean socialPersonFlag = false;
            boolean fundPersonFlag = false;
            boolean otherPersonFlag = false;
            for (InsuranceAccountDetailPO item : v) {
                // 判断社保是否为0
                socialPersonFlag = (StringUtils.isBlank(item.getSocialSum()) || SalaryEntityUtil.StringEqZERO(item.getSocialSum()));
                BigDecimal socialPerson = socialPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getSocialSum());
                fundPersonFlag = (StringUtils.isBlank(item.getFundSum()) || SalaryEntityUtil.StringEqZERO(item.getFundSum()));
                BigDecimal fundPerson = fundPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getFundSum());
                otherPersonFlag = (StringUtils.isBlank(item.getOtherSum()) || SalaryEntityUtil.StringEqZERO(item.getOtherSum()));
                BigDecimal otherPerson = otherPersonFlag ? new BigDecimal("0") : new BigDecimal(item.getOtherSum());
                socialTemp = socialTemp.add(socialPerson);
                fundTemp = fundTemp.add(fundPerson);
                otherTemp = otherTemp.add(otherPerson);
                if (!socialPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    socialAccountPerson += 1;
                }
                if (!fundPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    funcAccountPerson += 1;
                }
                if (!otherPersonFlag && !item.getPaymentStatus().equals(PaymentStatusEnum.BALANCE.getValue())) {
                    otherAccountPerson += 1;
                }
            }

            if (!"0".equals(socialTemp.toPlainString())) {
                socialSum = socialSum.add(socialTemp);
            }
            if (!"0".equals(fundTemp.toPlainString())) {
                fundSum = fundSum.add(fundTemp);
            }
            if (!"0".equals(otherTemp.toPlainString())) {
                otherSum = otherSum.add(otherTemp);
            }
        }
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(billMonth, param.getPaymentOrganization());
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);

        insuranceAccountBatchPO.setAccountant(user.getLastname());
        insuranceAccountBatchPO.setUpdateTime(new Date());
        insuranceAccountBatchPO.setSocialPay(socialSum.toPlainString());
        insuranceAccountBatchPO.setSocialNum(socialAccountPerson);
        insuranceAccountBatchPO.setFundNum(funcAccountPerson);
        insuranceAccountBatchPO.setFundPay(fundSum.toPlainString());
        insuranceAccountBatchPO.setOtherNum(otherAccountPerson);
        insuranceAccountBatchPO.setOtherPay(otherSum.toPlainString());
        encryptUtil.encrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        getInsuranceAccountBatchMapper().updateById(insuranceAccountBatchPO);
        //记录操作日志
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(insuranceAccountBatchPO.getPaymentOrganization());
        LoggerContext<InsuranceAccountBatchPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(insuranceAccountBatchPO.getId()));
        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "更新福利台账"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "更新福利台账")
                + ":" + taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setNewValues(insuranceAccountBatchPO);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
    }

    public void siFile(String billMonth, Long paymentOrganization) {

        //开始归档数据
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillStatus(billMonth, BillStatusEnum.NOT_ARCHIVED.getValue(), paymentOrganization);
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        SalaryAssert.notNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(0, "月份账单不存在"));
        SalaryAssert.isFalse(Objects.equals(insuranceAccountBatchPO.getBillStatus(), BillStatusEnum.ARCHIVED.getValue()), SalaryI18nUtil.getI18nLabel(0, "月份账单已归档"));
        insuranceAccountBatchPO.setBillStatus(BillStatusEnum.ARCHIVED.getValue());
        encryptUtil.encrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        getInsuranceAccountBatchMapper().updateById(insuranceAccountBatchPO);
        //记录操作日志
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(insuranceAccountBatchPO.getPaymentOrganization());
        LoggerContext<InsuranceAccountBatchPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId("" + insuranceAccountBatchPO.getId());
        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setOperateType(OperateTypeEnum.UPDATE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账-归档"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账-归档")
                + ": " + taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setNewValues(insuranceAccountBatchPO);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
    }


    public PageInfo<InsuranceAccountBatchPO> siBatchListPage(InsuranceAccountBatchParam queryParam) {
        List<InsuranceAccountBatchPO> list = getInsuranceAccountBatchMapper().list(queryParam);
        PageInfo<InsuranceAccountBatchPO> page = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                list, InsuranceAccountBatchPO.class);
        encryptUtil.decryptList(page.getList(), InsuranceAccountBatchPO.class);
        return page;
    }

    public PageInfo<InsuranceAccountDetailPO> siBatchListCommonPage(InsuranceAccountDetailParam queryParam) {
        queryParam.setPaymentStatus(PaymentStatusEnum.COMMON.getValue());
        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);
        //系统人员福利台账明细
        List<InsuranceAccountDetailPO> list = getInsuranceAccountDetailMapper().list(queryParam);
        //非系统各人员台账明细
        List<InsuranceAccountDetailPO> extList = getInsuranceAccountDetailMapper().extList(queryParam);
        list.addAll(extList);
        PageInfo<InsuranceAccountDetailPO> pageInfo = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(),
                list, InsuranceAccountDetailPO.class);
        encryptUtil.decryptList(pageInfo.getList(), InsuranceAccountDetailPO.class);
        return pageInfo;
    }

    public void siDelete(AccountParam param) {
        InsuranceAccountBatchPO insuranceAccountBatchPO = getInsuranceAccountBatchMapper().getByBillMonth(param.getBillMonth(), param.getPaymentOrganization());
        encryptUtil.decrypt(insuranceAccountBatchPO, InsuranceAccountBatchPO.class);
        SalaryAssert.notNull(insuranceAccountBatchPO, SalaryI18nUtil.getI18nLabel(0, "参数错误"));
//        if (insuranceAccountBatchPO.getBillStatus().equals(BillStatusEnum.ARCHIVED.getValue())) {
//            int num = checkIfBusinessAccounting(insuranceAccountBatchPO);
//            //表示已经被核算过不能重新核算
//            if (num > 0) {
//                throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "已被薪酬核算给核算过，无法删除！"));
//            }
//        }

//        if(param.getPaymentOrganization()==null){
//            throw new SalaryRunTimeException("个税扣缴义务人为空");
//        }
        getInsuranceAccountBatchMapper().deleteById(insuranceAccountBatchPO.getId());
        getInsuranceAccountDetailMapper().batchDeleteNotFile(param.getBillMonth(), param.getPaymentOrganization());
        //删除账单月份+个税扣缴义务人下的调差数据
        getInsuranceCompensationMapper().deleteByBillMonthAndPayOrg(param.getBillMonth(), param.getPaymentOrganization());
        //记录操作日志
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(insuranceAccountBatchPO.getPaymentOrganization());
        LoggerContext<InsuranceAccountBatchPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(String.valueOf(insuranceAccountBatchPO.getId()));
        loggerContext.setTargetName(taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "删除福利台账"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "删除福利台账")
                + ":" + taxAgentInfo.getName() + "-" + insuranceAccountBatchPO.getBillMonth());
        loggerContext.setNewValues(insuranceAccountBatchPO);
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
    }

    public void siSaveSupplementaryAccount(SaveSupplementaryAccountParam param) {
        if (StringUtils.isBlank(param.getBillMonth()) || CollectionUtils.isEmpty(param.getBillMonthList()) || CollectionUtils.isEmpty(param.getProjects())
                || CollectionUtils.isEmpty(param.getIncludes())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "参数错误"));
        }
        //需要补缴的月份
        if (param.getBillMonthList().contains(param.getBillMonth())) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "当前月走正常缴纳"));
        }
        //需要补缴的员工id
        List<Long> employeeIds = param.getIncludes();
        if (CollectionUtils.isNotEmpty(param.getExcludes())) {
            employeeIds = employeeIds.stream().filter(item -> !param.getExcludes().contains(item)).collect(Collectors.toList());
        }
        //校验补缴人员是否存在福利档案基础信息，并且runStatus处于正在缴纳或者待减员
        List<InsuranceArchivesBaseInfoPO> insuranceBaseInfoList = getInsuranceBaseInfoMapper().getSocialByPaymentOrganization(param.getPaymentOrganization());
        List<Long> finalEmployeeIds = employeeIds;
        List<InsuranceArchivesBaseInfoPO> filterList = insuranceBaseInfoList.stream().filter(e -> {
            for (Long uId : finalEmployeeIds) {
                if (e.getEmployeeId().equals(uId) && (e.getRunStatus().equals(EmployeeStatusEnum.STAY_DEL.getValue()) || e.getRunStatus().equals(EmployeeStatusEnum.PAYING.getValue()))) {
                    return true;
                }
            }
            return false;
        }).collect(Collectors.toList());
        if (filterList.size() != employeeIds.size()) {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "补缴人员中存在未设置福利档案人员或相关人员不在福利在缴人员中，不可新建补缴信息！"));
        }
        //20231122逻辑优化，过滤出不在起始缴纳月和最后缴纳月区间的人员
        List<Long> empIdsInPayMonthRange = listCanPayEmpIds(param.getPaymentOrganization(), param.getBillMonth());
        employeeIds = employeeIds.stream().filter(f -> empIdsInPayMonthRange.contains(f)).collect(Collectors.toList());

        SalaryAssert.notEmpty(employeeIds, SalaryI18nUtil.getI18nLabel(0, "无核算人员"));
        List<SupplementAccountBaseParam> baseList = new ArrayList<>();
        employeeIds.stream().forEach(id -> {
            param.getBillMonthList().stream().forEach(month -> {
                SupplementAccountBaseParam supplementAccountBaseParam = SupplementAccountBaseParam.builder()
                        .supplementaryMonth(month)
                        .employeeId(id)
                        .paymentOrganization(param.getPaymentOrganization())
                        .projects(param.getProjects())
                        .billMonth(param.getBillMonth())
                        .supplementType(param.getSupplementType())
                        .build();
                if ("2".equals(param.getSupplementType())) {
                    supplementAccountBaseParam.setSocialPaymentBaseString(param.getSocialPaymentBaseString());
                    supplementAccountBaseParam.setFundPaymentBaseString(param.getFundPaymentBaseString());
                    supplementAccountBaseParam.setOtherPaymentBaseString(param.getOtherPaymentBaseString());
                } else if("3".equals(param.getSupplementType())) {
                    supplementAccountBaseParam.setSocialPaymentPerString(param.getSocialPaymentPerString());
                    supplementAccountBaseParam.setSocialPaymentComString(param.getSocialPaymentComString());
                    supplementAccountBaseParam.setFundPaymentPerString(param.getFundPaymentPerString());
                    supplementAccountBaseParam.setFundPaymentComString(param.getFundPaymentComString());
                    supplementAccountBaseParam.setOtherPaymentPerString(param.getOtherPaymentPerString());
                    supplementAccountBaseParam.setOtherPaymentComString(param.getOtherPaymentComString());
                }
                baseList.add(supplementAccountBaseParam);
            });
        });
        //核算开始
        accountSupplement(baseList, employeeIds, param.getPaymentOrganization());

        updateBatchAccount(AccountParam.builder().billMonth(param.getBillMonth()).paymentOrganization(param.getPaymentOrganization()).build());
    }

    /**
     * @param baseList    员工id-账单月份-补缴月份（单挑）-补缴项 集合
     * @param employeeIds 需要补缴的员工id
     * @return
     */
    public String accountSupplement(List<SupplementAccountBaseParam> baseList, List<Long> employeeIds, Long paymentOrganization) {
        //(k,v) k-员工id v-员工对应的福利档案数据
//        Map<Long, InsuranceArchivesAccountPO> longInsuranceArchivesAccountPOMap = siArchivesBiz.buildBatchAccount(employeeIds, paymentOrganization);
        Map<Long, InsuranceArchivesAccountPO> longInsuranceArchivesAccountPOMap = getSIArchivesService(user).buildBatchAccount(employeeIds, paymentOrganization);
        //核算结果集
        List<InsuranceAccountDetailPO> pos = new ArrayList<>();
        baseList.forEach(baseParam -> {
            //判断人员id+账单月份+补缴月份在表中的唯一性
            List<InsuranceAccountDetailPO> supplementList = getInsuranceAccountDetailMapper().querySupplementList(baseParam.getBillMonth(), baseParam.getPaymentOrganization(), baseParam.getEmployeeId(), baseParam.getSupplementaryMonth());
            if (supplementList.size() > 0) {
                throw new SalaryRunTimeException("当前人员和账单月份已存在该补缴月份的数据！无法再次创建！");
            }
            InsuranceAccountDetailPO insuranceAccountDetailPO = accountSingleEmployeeBill(baseParam, longInsuranceArchivesAccountPOMap.get(baseParam.getEmployeeId()));
            pos.add(insuranceAccountDetailPO);
        });
        batchSaveSupplementAccount(pos);
        return SalaryI18nUtil.getI18nLabel(0, "核算完成,数据保存成功");
    }

    public InsuranceAccountDetailPO accountSingleEmployeeBill(SupplementAccountBaseParam baseParam, InsuranceArchivesAccountPO accountPO) {
        InsuranceAccountDetailPO insuranceAccountDetailPO = new InsuranceAccountDetailPO();
        List<Integer> projects = baseParam.getProjects();
        insuranceAccountDetailPO.setBillMonth(baseParam.getBillMonth());
        insuranceAccountDetailPO.setBillStatus(BillStatusEnum.NOT_ARCHIVED.getValue());
        insuranceAccountDetailPO.setCreator((long) user.getUID());
        insuranceAccountDetailPO.setCreateTime(new Date());
        insuranceAccountDetailPO.setUpdateTime(new Date());
        insuranceAccountDetailPO.setDeleteType(DeleteTypeEnum.NOT_DELETED.getValue());
        insuranceAccountDetailPO.setId(IdGenerator.generate());
        insuranceAccountDetailPO.setEmployeeId(baseParam.getEmployeeId());
        insuranceAccountDetailPO.setPaymentStatus(PaymentStatusEnum.REPAIR.getValue());
        insuranceAccountDetailPO.setSupplementaryMonth(baseParam.getSupplementaryMonth());
        insuranceAccountDetailPO.setPaymentOrganization(baseParam.getPaymentOrganization());
        insuranceAccountDetailPO.setSupplementaryProjects(
                String.join(",",
                        baseParam.getProjects() == null ? new ArrayList<>() : baseParam.getProjects().stream().map(String::valueOf).collect(Collectors.toList())));
        insuranceAccountDetailPO.setTenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY);
        insuranceAccountDetailPO.setResourceFrom(ResourceFromEnum.SYSTEM.getValue());
        //缴纳组织=个税扣缴义务人
        insuranceAccountDetailPO.setSocialPayOrg(baseParam.getPaymentOrganization());
        if (projects.contains(ProjectTypeEnum.ALL.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                if (accountPO.getFund() != null) {
                    accountPO.getFund().setFundPaymentBaseString(baseParam.getFundPaymentBaseString());
                }
                if (accountPO.getOther() != null) {
                    accountPO.getOther().setOtherPaymentBaseString(baseParam.getOtherPaymentBaseString());
                }
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSupSocialByData(insuranceAccountDetailPO, baseParam);
                accountSupFundByData(insuranceAccountDetailPO, baseParam);
                accountSupOtherByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

            return account(insuranceAccountDetailPO);
        }
        if (projects.contains(ProjectTypeEnum.SOCIAL.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSupSocialByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountSocial(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

        }
        if (!projects.contains(ProjectTypeEnum.SOCIAL.getValue())) {
            List<Long> ids = new ArrayList<>();
            List<ICategoryPO> list = getICategoryMapper().listByDataType(DataTypeEnum.SYSTEM.getValue());

            if (projects.contains(ProjectTypeEnum.ENDOWMENT_INSURANCE.getValue())) {
                ICategoryPO insuranceCategoryPO = list.stream().filter(item -> SalaryI18nUtil.getI18nLabel(0, "养老保险").equals(item.getInsuranceName())).findFirst()
                        .get();
                ids.add(insuranceCategoryPO.getId());
            }
            if (projects.contains(ProjectTypeEnum.MEDICAL_INSURANCE.getValue())) {
                ICategoryPO insuranceCategoryPO = list.stream().filter(item -> SalaryI18nUtil.getI18nLabel(0, "医疗保险").equals(item.getInsuranceName())).findFirst()
                        .get();
                ids.add(insuranceCategoryPO.getId());
            }
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getSocial() != null) {
                    accountPO.getSocial().setSocialPaymentBaseString(baseParam.getSocialPaymentBaseString());
                }
                accountEndowmentInsurance(insuranceAccountDetailPO, accountPO, ids, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSupEndowmentInsuranceByData(insuranceAccountDetailPO, baseParam, ids);
            } else {
                accountEndowmentInsurance(insuranceAccountDetailPO, accountPO, ids, baseParam.getSupplementaryMonth());
            }

        }
        if (projects.contains(ProjectTypeEnum.FUND.getValue())) {
            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getFund() != null) {
                    accountPO.getFund().setFundPaymentBaseString(baseParam.getFundPaymentBaseString());
                }
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSupFundByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountFund(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }
        }
        if (projects.contains(ProjectTypeEnum.OTHER.getValue())) {

            if ("2".equals(baseParam.getSupplementType())) {
                if (accountPO.getOther() != null) {
                    accountPO.getOther().setOtherPaymentBaseString(baseParam.getOtherPaymentBaseString());
                }
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            } else if ("3".equals(baseParam.getSupplementType())) {
                accountSupOtherByData(insuranceAccountDetailPO, baseParam);
            } else {
                accountOther(insuranceAccountDetailPO, accountPO, baseParam.getSupplementaryMonth());
            }

        }

        return account(insuranceAccountDetailPO);
    }

    public void accountSupFundByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //公积金个人
        if (StringUtils.isNotBlank(baseParam.getFundPaymentPerString())) {
            List<BigDecimal> fundPer = new ArrayList<>();
            HashMap<String, String> fundPerson = JSON.parseObject(baseParam.getFundPaymentPerString(), new HashMap<String, String>().getClass());
            fundPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundPer.add(result);
            });
            insuranceAccountDetailPO.setFundPerJson(baseParam.getFundPaymentPerString());
            BigDecimal fundPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundPer) {
                fundPerSum = fundPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundPerSum(fundPerSum.toPlainString());
        }
        //公积金单位
        if (StringUtils.isNotBlank(baseParam.getFundPaymentComString())) {
            List<BigDecimal> fundCom = new ArrayList<>();
            HashMap<String, String> fundComMap = JSON.parseObject(baseParam.getFundPaymentComString(), new HashMap<String, String>().getClass());
            fundComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                fundCom.add(result);
            });
            insuranceAccountDetailPO.setFundComJson(baseParam.getFundPaymentComString());
            BigDecimal fundComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : fundCom) {
                fundComSum = fundComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setFundComSum(fundComSum.toPlainString());
        }
    }

    public void accountSupOtherByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //其他福利个人
        if (StringUtils.isNotBlank(baseParam.getOtherPaymentPerString())) {
            List<BigDecimal> otherPer = new ArrayList<>();
            HashMap<String, String> otherPerMap = JSON.parseObject(baseParam.getOtherPaymentPerString(), new HashMap<String, String>().getClass());
            otherPerMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherPer.add(result);
            });
            insuranceAccountDetailPO.setOtherPerJson(baseParam.getOtherPaymentPerString());
            BigDecimal otherPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherPer) {
                otherPerSum = otherPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherPerSum(otherPerSum.toPlainString());
        }
        //其他福利单位
        if (StringUtils.isNotBlank(baseParam.getOtherPaymentComString())) {
            List<BigDecimal> otherCom = new ArrayList<>();
            HashMap<String, String> otherComMap = JSON.parseObject(baseParam.getOtherPaymentComString(), new HashMap<String, String>().getClass());
            otherComMap.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                otherCom.add(result);
            });
            insuranceAccountDetailPO.setOtherComJson(baseParam.getOtherPaymentComString());
            BigDecimal otherComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : otherCom) {
                otherComSum = otherComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setOtherComSum(otherComSum.toPlainString());
        }
    }

    public void accountSupSocialByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam) {
        //社保个人
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentPerString())) {
            List<BigDecimal> socialPer = new ArrayList<>();
            HashMap<String, String> archivesPerson = JSON.parseObject(baseParam.getSocialPaymentPerString(), new HashMap<String, String>().getClass());
            archivesPerson.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialPer.add(result);
            });
            insuranceAccountDetailPO.setSocialPerJson(baseParam.getSocialPaymentPerString());
            BigDecimal socialPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialPer) {
                socialPerSum = socialPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
        }
        //社保单位
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentComString())) {
            List<BigDecimal> socialCom = new ArrayList<>();
            HashMap<String, String> archivesCom = JSON.parseObject(baseParam.getSocialPaymentComString(), new HashMap<String, String>().getClass());
            archivesCom.forEach((k, v) -> {
                BigDecimal result = new BigDecimal(v);
                socialCom.add(result);
            });
            insuranceAccountDetailPO.setSocialComJson(baseParam.getSocialPaymentComString());
            BigDecimal socialComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialCom) {
                socialComSum = socialComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        }
    }

    public InsuranceAccountDetailPO accountEndowmentInsurance(InsuranceAccountDetailPO insuranceAccountDetailPO, InsuranceArchivesAccountPO accountPO, List<Long> categoryIds, String billMonth) {
        if (accountPO.getSocial() != null) {
            InsuranceArchivesSocialSchemePO socialPO = accountPO.getSocial();
            insuranceAccountDetailPO.setSocialPayOrg(socialPO.getPaymentOrganization());
            insuranceAccountDetailPO.setSocialAccount(socialPO.getSocialAccount());
            insuranceAccountDetailPO.setSocialSchemeId(socialPO.getSocialSchemeId());
            insuranceAccountDetailPO.setSocialPaymentBaseString(socialPO.getSocialPaymentBaseString());
            insuranceAccountDetailPO.setSocialPaymentComBaseString(socialPO.getSocialPaymentComBaseString());
            //判断是否在起始缴纳月和最后缴纳月之间
            Boolean inDataRange = SalaryDateUtil.monthInRange(billMonth, socialPO.getSocialStartTime(), socialPO.getSocialEndTime());

            if ((Objects.equals(NonPaymentEnum.YES.getValue(), socialPO.getNonPayment()) || socialPO.getNonPayment() == null) && socialPO.getSocialSchemeId() != null && inDataRange) {
                List<InsuranceSchemeDetailPO> detailPOS = getInsuranceSchemeDetailMapper().queryListBySchemeId(socialPO.getSocialSchemeId());
                encryptUtil.decryptList(detailPOS, InsuranceSchemeDetailPO.class);
                //方案中包含的需要缴纳社保的个人福利
                int monthIndex = Integer.parseInt(billMonth.split("-")[1]) - 1;
                Map<Long, InsuranceSchemeDetailPO> schemeperson = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment())
                                && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_PERSON.getValue())
                                && (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesPerson = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  个人
                List<Long> needArchivesPerson = new ArrayList<>();
                if (archivesPerson != null) {
                    categoryIds.forEach(item -> {
                        if (archivesPerson.containsKey(String.valueOf(item)) && schemeperson.containsKey(item)) {
                            if (StringUtils.isNotBlank(archivesPerson.get(String.valueOf(item)))) {
                                needArchivesPerson.add(item);
                            }
                        }
                    });
                }
                //判断核算周期、核算月、福利起始缴纳月的关系
                checkCycleSettingWithStartMonth(schemeperson, billMonth, socialPO.getSocialStartTime());

                List<BigDecimal> socialPer = new ArrayList<>();
                Map<String, String> socialPerJsonMap = new HashMap<>();
                needArchivesPerson.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeperson.get(e);
                    BigDecimal paymentProportion = new BigDecimal(po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesPerson) || StringUtils.isBlank(archivesPerson.get(String.valueOf(e)))) ? "0" : archivesPerson.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }
                    socialPerJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialPer.add(result);
                });
                insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerJsonMap));
                BigDecimal socialPerSum = new BigDecimal("0");
                for (BigDecimal bigDecimal : socialPer) {
                    socialPerSum = socialPerSum.add(bigDecimal);
                }
                insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
                //方案中包含的需要缴纳社保的单位福利
                Map<Long, InsuranceSchemeDetailPO> schemeCom = detailPOS.stream()
                        .filter(item -> Objects.equals(IsPaymentEnum.YES.getValue(), item.getIsPayment()) && Objects.equals(item.getPaymentScope(), PaymentScopeEnum.SCOPE_COMPANY.getValue()) &&
                                (item.getPaymentCycle() == null || item.getPaymentCycle() == 0 || (item.getPaymentCycle() == 1 && String.valueOf(item.getCycleSetting().charAt(monthIndex)).equals("1"))))
                        .collect(
                                Collectors.toMap(InsuranceSchemeDetailPO::getInsuranceId, Function.identity()));
                //档案中包含的基数信息
                HashMap<String, String> archivesCom = JSON.parseObject(socialPO.getSocialPaymentBaseString(), new HashMap<String, String>().getClass());
                //需要核算社保的福利id  单位
                List<Long> needArchivesCom = new ArrayList<>();
                if (archivesCom != null) {
                    categoryIds.forEach(item -> {
                        if (archivesCom.containsKey(String.valueOf(item)) && schemeCom.containsKey(item)) {
                            if (StringUtils.isNotBlank(archivesCom.get(String.valueOf(item)))) {
                                needArchivesCom.add(item);
                            }
                        }
                    });
                    //判断核算周期、核算月、福利起始缴纳月的关系
                    checkCycleSettingWithStartMonth(schemeCom, billMonth, socialPO.getSocialStartTime());
                }
                List<BigDecimal> socialCom = new ArrayList<>();
                Map<String, String> sociaComJsonMap = new HashMap<>();
                needArchivesCom.forEach(e -> {
                    InsuranceSchemeDetailPO po = schemeCom.get(e);
                    BigDecimal paymentProportion = new BigDecimal(po.getPaymentProportion()).divide(new BigDecimal("100"));
                    BigDecimal paymentNum = new BigDecimal((ObjectUtil.isEmpty(archivesCom) || StringUtils.isBlank(archivesCom.get(String.valueOf(e)))) ? "0" : archivesCom.get(String.valueOf(e)));
                    BigDecimal fixedCost = StringUtils.isBlank(po.getFixedCost()) ? new BigDecimal("0") : new BigDecimal(po.getFixedCost());
                    Integer newScale = po.getValidNum() == null ? 0 : po.getValidNum();
                    BigDecimal result = new BigDecimal("0");
                    if (Objects.equals(po.getPaymentCycle(), 1)) {
                        int monthValue = 1;
                        for (int i = monthIndex - 1; i >= 0; i--) {
                            String cycleValue = po.getCycleSetting().charAt(i) + "";
                            if (Integer.parseInt(cycleValue) == 1) {
                                break;
                            }
                            monthValue++;
                        }
                        if (po.getAccountType() == 1) {
                            paymentNum = paymentNum.multiply(new BigDecimal(monthValue));
                            fixedCost = fixedCost.multiply(new BigDecimal(monthValue));
                            result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                        } else {
                            for (int i = 0; i < monthValue; i++) {
                                result = result.add(SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost)));
                            }
                        }
                    } else {
                        result = SalaryEntityUtil.carryRule(newScale, po.getRententionRule(), paymentNum.multiply(paymentProportion).add(fixedCost));
                    }

                    sociaComJsonMap.put(String.valueOf(e), result.toPlainString());
                    socialCom.add(result);

                });
                insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(sociaComJsonMap));
                BigDecimal socialComSum = new BigDecimal("0");
                for (BigDecimal decimal : socialCom) {
                    socialComSum = socialComSum.add(decimal);
                }
                insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
            }
        }
        return insuranceAccountDetailPO;
    }

    public void accountSupEndowmentInsuranceByData(InsuranceAccountDetailPO insuranceAccountDetailPO, SupplementAccountBaseParam baseParam, List<Long> ids) {
        //社保个人
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentPerString())) {
            List<BigDecimal> socialPer = new ArrayList<>();
            HashMap<String, String> archivesPerson = JSON.parseObject(baseParam.getSocialPaymentPerString(), new HashMap<String, String>().getClass());
            HashMap<String, String> socialPerson = new HashMap<>();
            archivesPerson.forEach((k, v) -> {
                if (ids.contains(Long.valueOf(k))) {
                    socialPerson.put(k, v);
                    BigDecimal result = new BigDecimal(v);
                    socialPer.add(result);
                }

            });
            insuranceAccountDetailPO.setSocialPerJson(JSON.toJSONString(socialPerson));
            BigDecimal socialPerSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialPer) {
                socialPerSum = socialPerSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialPerSum(socialPerSum.toPlainString());
        }
        //社保单位
        if (StringUtils.isNotBlank(baseParam.getSocialPaymentComString())) {
            List<BigDecimal> socialCom = new ArrayList<>();
            HashMap<String, String> archivesCom = JSON.parseObject(baseParam.getSocialPaymentComString(), new HashMap<String, String>().getClass());
            HashMap<String, String> socialComMap = new HashMap<>();
            archivesCom.forEach((k, v) -> {
                if (ids.contains(Long.valueOf(k))) {
                    socialComMap.put(k, v);
                    BigDecimal result = new BigDecimal(v);
                    socialCom.add(result);
                }
            });
            insuranceAccountDetailPO.setSocialComJson(JSON.toJSONString(socialComMap));
            BigDecimal socialComSum = new BigDecimal("0");
            for (BigDecimal bigDecimal : socialCom) {
                socialComSum = socialComSum.add(bigDecimal);
            }
            insuranceAccountDetailPO.setSocialComSum(socialComSum.toPlainString());
        }
    }

    public void batchSaveSupplementAccount(List<InsuranceAccountDetailPO> pos) {
        if (CollectionUtils.isEmpty(pos)) {
            return;
        }
        batchSaveAccountInspectDetail(pos);
        getInsuranceAccountDetailMapper().batchDelSupplementAccountDetails(pos);
        encryptUtil.encryptList(pos, InsuranceAccountDetailPO.class);
        List<List<InsuranceAccountDetailPO>> lists = splitDetailList(pos, 20);
        lists.forEach(subList -> {
            getInsuranceAccountDetailMapper().batchSaveAccountDetails(subList);
        });
        //删除日志
//        pos.stream().forEach(item -> {
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetId(String.valueOf(item.getId()));
//            insuranceSchemeContext.setTargetName(String.valueOf(item.getEmployeeId()));
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.DELETE.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(100448, "删除核算记录"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(100448, "删除核算记录"));
//            insuranceSchemeContext.setNewValues(item);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
//        });
        //插入日志
//        pos.stream().forEach(item -> {
//            LoggerContext insuranceSchemeContext = new LoggerContext();
//            insuranceSchemeContext.setTargetId(String.valueOf(item.getId()));
//            insuranceSchemeContext.setTargetName(String.valueOf(item.getEmployeeId()));
//            insuranceSchemeContext.setOperateType(OperateTypeEnum.ADD.getValue());
//            insuranceSchemeContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(100494, "新建核算记录"));
//            insuranceSchemeContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(100494, "新建核算记录"));
//            insuranceSchemeContext.setNewValues(item);
//            siAccountLoggerTemplate.write(insuranceSchemeContext);
//        });
        //记录操作日志
        encryptUtil.decryptList(pos, InsuranceAccountDetailPO.class);
        InsuranceAccountBatchPO targetPO = getInsuranceAccountBatchMapper().getByBillMonth(pos.get(0).getBillMonth(), pos.get(0).getPaymentOrganization());
        TaxAgentPO taxAgentInfo = getTaxAgentMapper().getById(targetPO.getPaymentOrganization());
        pos.forEach(targetDetailPO -> {
            DataCollectionEmployee empInfo = getEmployMapper().getEmployeeById(targetDetailPO.getEmployeeId());
            LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId("" + targetPO.getId());
            loggerContext.setTargetName(taxAgentInfo.getName() + "-" + targetPO.getBillMonth() + "-" + empInfo.getUsername());
            loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-新增补缴"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-新增补缴")
                    + ": " + taxAgentInfo.getName() + "-" + targetPO.getBillMonth() + "-" + empInfo.getUsername());
            loggerContext.setNewValues(targetDetailPO);
            SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);
        });
    }

    public void siDeleteCommonAccount(SaveCommonAccountParam param) {
        ValidUtil.doValidator(param);
        //根据id批量删除
        if (param.getIds().size() > 0) {
            getInsuranceAccountDetailMapper().batchDelAccountDetailsByIds(param.getIds());
        } else {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "请勾选需要删除的数据项！"));
        }
        //记录操作日志
        LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(param.getIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
        loggerContext.setTargetName(param.getIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
        loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-删除正常缴纳核算记录"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-删除正常缴纳核算记录"));
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);

        updateBatchAccount(AccountParam.builder().billMonth(param.getBillMonth()).paymentOrganization(param.getPaymentOrganization()).build());
    }

    public void siDeleteSupplementaryAccount(SaveCommonAccountParam param) {
        ValidUtil.doValidator(param);
        //根据id批量删除
        if (param.getIds().size() > 0) {
            getInsuranceAccountDetailMapper().batchDelAccountDetailsByIds(param.getIds());
        } else {
            throw new SalaryRunTimeException(SalaryI18nUtil.getI18nLabel(0, "请勾选需要删除的数据项！"));
        }
        getInsuranceAccountDetailMapper().batchDelAccountDetailsByIds(param.getIds());
        //记录操作日志
        LoggerContext<InsuranceAccountDetailPO> loggerContext = new LoggerContext();
        loggerContext.setUser(user);
        loggerContext.setTargetId(param.getIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
        loggerContext.setTargetName(param.getIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
        loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-删除补缴核算记录"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "福利台账明细表-删除补缴核算记录"));
        SalaryElogConfig.siAccountLoggerTemplate.write(loggerContext);

        updateBatchAccount(AccountParam.builder().billMonth(param.getBillMonth()).paymentOrganization(param.getPaymentOrganization()).build());
    }

    public void accountInspect(Collection<Long> ids, String billMonth, Long paymentOrganization) {
        List<InsuranceAccountInspectPO> insuranceAccountInspectPOS = allInspects(ids, billMonth);
        SalaryAssert.notEmpty(insuranceAccountInspectPOS, SalaryI18nUtil.getI18nLabel(0, "无核算数据"));
        List<InsuranceAccountInspectPO> commonInspects = insuranceAccountInspectPOS.stream()
                .filter(e -> Objects.equals(e.getPaymentStatus(), PaymentStatusEnum.COMMON.getValue()))
                .collect(Collectors.toList());
        List<InsuranceAccountInspectPO> supplementInspects = insuranceAccountInspectPOS.stream()
                .filter(e -> Objects.equals(e.getPaymentStatus(), PaymentStatusEnum.REPAIR.getValue()))
                .collect(Collectors.toList());
        //核算正常缴纳
        if (CollectionUtils.isNotEmpty(commonInspects)) {
            SaveCommonAccountParam param = new SaveCommonAccountParam();
            param.setBillMonth(billMonth);
            param.setIncludes(commonInspects.stream().map(InsuranceAccountInspectPO::getEmployeeId).collect(Collectors.toList()));
            siSaveCommonAccount(param);
        }
        //核算补缴
        if (CollectionUtils.isNotEmpty(supplementInspects)) {
            List<SupplementAccountBaseParam> baseList = new ArrayList<>();
            supplementInspects.forEach(e -> {
                SupplementAccountBaseParam base = new SupplementAccountBaseParam();
                base.setBillMonth(billMonth);
                base.setProjects(
                        e.getSupplementaryProjects() == null ? null : Arrays.stream(e.getSupplementaryProjects().split(",")).map(Integer::valueOf).collect(Collectors.toList()));
                base.setEmployeeId(e.getEmployeeId());
                base.setSupplementaryMonth(e.getSupplementaryMonth());
                baseList.add(base);
            });
            accountSupplement(baseList, baseList.stream().map(SupplementAccountBaseParam::getEmployeeId).collect(Collectors.toList()), paymentOrganization);
        }
    }

    public PageInfo<InsuranceAccountViewListDTO> siOverView(InsuranceAccountDetailParam queryParam) {

        List<InsuranceAccountDetailPO> insuranceAccountDetailPOS = getInsuranceAccountDetailMapper().selectList(queryParam.getBillMonth(), StringUtil.isBlank(queryParam.getPaymentOrganization()) ? null : Long.valueOf(queryParam.getPaymentOrganization()));
        encryptUtil.decryptList(insuranceAccountDetailPOS, InsuranceAccountDetailPO.class);
        //获取扣缴义务人信息
        List<TaxAgentPO> paymentList = getTaxAgentMapper().listAll();
        SalaryAssert.notEmpty(paymentList, SalaryI18nUtil.getI18nLabel(0, "该租户无扣缴义务人"));
        Map<Long, TaxAgentPO> paymentMap = paymentList.stream().collect(Collectors.toMap(TaxAgentPO::getId, Function.identity()));
        List<InsuranceAccountViewListDTO> insuranceAccountViewListDTOS = buildRecords(insuranceAccountDetailPOS, paymentMap);

        PageInfo<InsuranceAccountViewListDTO> insuranceAccountViewListDTOPage = new PageInfo<>(insuranceAccountViewListDTOS, InsuranceAccountViewListDTO.class);
        insuranceAccountViewListDTOPage.setTotal(insuranceAccountViewListDTOS.size());
        return insuranceAccountViewListDTOPage;
    }

    @Override
    public List<InsuranceAccountViewListDTO> buildRecords(List<InsuranceAccountDetailPO> list, Map<Long, TaxAgentPO> paymentMap) {
        Map<Long, InsuranceAccountViewListDTO> result = new HashMap<>();
        //根据组织分组,对社保进行统计
        Map<Long, List<InsuranceAccountDetailPO>> socialCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        socialCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountSocialView(insuranceAccountViewListDTO, v);
        });
        //根据组织分组，对公积金进行统计
        Map<Long, List<InsuranceAccountDetailPO>> fundCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        fundCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountFundView(insuranceAccountViewListDTO, v);
        });
        //根据组织分组,对其他福利进行统计
        Map<Long, List<InsuranceAccountDetailPO>> otherCollect = list.stream().filter(item -> item.getSocialPayOrg() != null)
                .collect(Collectors.groupingBy(InsuranceAccountDetailPO::getSocialPayOrg));
        otherCollect.forEach((k, v) -> {
            if (result.get(k) == null) {
                InsuranceAccountViewListDTO temp = new InsuranceAccountViewListDTO();
                temp.setPayOrg(paymentMap.get(k).getName());
                result.put(k, temp);
            }
            InsuranceAccountViewListDTO insuranceAccountViewListDTO = result.get(k);
            accountOtherView(insuranceAccountViewListDTO, v);
        });
        //对各组织进行金额合计
        List<InsuranceAccountViewListDTO> viewDTOS = new ArrayList<>();
        result.forEach((k, v) -> {
            BigDecimal socialPaySum = StringUtils.isBlank(v.getSocialPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getSocialPaySum());
            BigDecimal fundPaySum = StringUtils.isBlank(v.getFundPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getFundPaySum());
            BigDecimal otherPaySum = StringUtils.isBlank(v.getOtherPaySum()) ? new BigDecimal("0") : new BigDecimal(v.getOtherPaySum());
            v.setIndex(k);
            BigDecimal sum = socialPaySum.add(fundPaySum).add(otherPaySum);
            v.setSum(sum.toPlainString());
            viewDTOS.add(v);
        });
        //合计
        InsuranceAccountViewListDTO insuranceAccountViewListDTO = new InsuranceAccountViewListDTO();
        int socialNum = 0;
        int fundNum = 0;
        int otherNum = 0;
        BigDecimal socialSum = new BigDecimal("0");
        BigDecimal fundSum = new BigDecimal("0");
        BigDecimal otherSum = new BigDecimal("0");
        BigDecimal sum = new BigDecimal("0");
        for (InsuranceAccountViewListDTO item : viewDTOS) {
            if (item.getSocialNum() != null) {
                socialNum += item.getSocialNum();
            }
            if (item.getFundNum() != null) {
                fundNum += item.getFundNum();
            }
            if (item.getOtherNum() != null) {
                otherNum += item.getOtherNum();
            }
            if (StringUtils.isNotBlank(item.getSocialPaySum())) {
                socialSum = socialSum.add(new BigDecimal(item.getSocialPaySum()));
            }
            if (StringUtils.isNotBlank(item.getFundPaySum())) {
                fundSum = fundSum.add(new BigDecimal(item.getFundPaySum()));
            }
            if (StringUtils.isNotBlank(item.getOtherPaySum())) {
                otherSum = otherSum.add(new BigDecimal(item.getOtherPaySum()));
            }
            if (StringUtils.isNotBlank(item.getSum())) {
                sum = sum.add(new BigDecimal(item.getSum()));
            }
        }
        insuranceAccountViewListDTO.setSum(sum.toPlainString());
        insuranceAccountViewListDTO.setSocialPaySum(socialSum.toPlainString());
        insuranceAccountViewListDTO.setPayOrg(SalaryI18nUtil.getI18nLabel(0, "合计"));
        insuranceAccountViewListDTO.setFundPaySum(fundSum.toPlainString());
        insuranceAccountViewListDTO.setOtherPaySum(otherSum.toPlainString());
        insuranceAccountViewListDTO.setSocialNum(socialNum);
        insuranceAccountViewListDTO.setFundNum(fundNum);
        insuranceAccountViewListDTO.setOtherNum(otherNum);
        viewDTOS.add(insuranceAccountViewListDTO);
        viewDTOS.forEach(e -> {
            e.setSocialPaySum(StringUtils.isBlank(e.getSocialPaySum()) ? "0" : e.getSocialPaySum());
            e.setSocialNum(e.getSocialNum() == null ? 0 : e.getSocialNum());
            e.setFundNum(e.getFundNum() == null ? 0 : e.getFundNum());
            e.setFundPaySum(StringUtils.isBlank(e.getFundPaySum()) ? "0" : e.getFundPaySum());
            e.setOtherPaySum(StringUtils.isBlank(e.getOtherPaySum()) ? "0" : e.getOtherPaySum());
            e.setOtherNum(e.getOtherNum() == null ? 0 : e.getOtherNum());
            e.setSum(SalaryEntityUtil.thousandthConvert(e.getSum()));
            e.setSocialPaySum(SalaryEntityUtil.thousandthConvert(e.getSocialPaySum()));
            e.setOtherPaySum(SalaryEntityUtil.thousandthConvert(e.getOtherPaySum()));
            e.setFundPaySum(SalaryEntityUtil.thousandthConvert(e.getFundPaySum()));
        });
        return viewDTOS;
    }

    @Override
    public void cacheWelfareField(List<String> welfareNames) {
        String cacheKey = user.getUID() + SalaryItemConstant.SI_ACCOUNT_IMPORT_FIELD_SIGN;
        Util_DataCache.setObjVal(cacheKey, JsonUtil.toJsonString(welfareNames));
    }

    @Override
    public void cacheBalanceWelfareField(List<String> welfareNames) {
        String cacheKey = user.getUID() + SalaryItemConstant.SI_ACCOUNT_BALANCE_IMPORT_FIELD_SIGN;
        Util_DataCache.setObjVal(cacheKey, JsonUtil.toJsonString(welfareNames));
    }

    public void accountOtherView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int otherNum = 0;
        BigDecimal otherPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getOtherSum()) && SalaryEntityUtil.string2DoubleDefault0(item.getOtherSum()) != 0.0) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    otherNum += 1;
                }
                otherPaySum = otherPaySum.add(new BigDecimal(item.getOtherSum()));
            }
        }
        dto.setOtherNum(otherNum);
        dto.setOtherPaySum(otherPaySum.toPlainString());
    }

    public void accountFundView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int fundNum = 0;
        BigDecimal fundPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getFundSum()) && SalaryEntityUtil.string2DoubleDefault0(item.getFundSum()) != 0.0) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    fundNum += 1;
                }
                fundPaySum = fundPaySum.add(new BigDecimal(item.getFundSum()));
            }
        }
        dto.setFundNum(fundNum);
        dto.setFundPaySum(fundPaySum.toPlainString());
    }

    public void accountSocialView(InsuranceAccountViewListDTO dto, List<InsuranceAccountDetailPO> pos) {
        int socialNum = 0;
        BigDecimal socialPaySum = new BigDecimal("0");
        for (InsuranceAccountDetailPO item : pos) {
            if (StringUtils.isNotBlank(item.getSocialSum()) &&  SalaryEntityUtil.string2DoubleDefault0(item.getSocialSum()) != 0.0 ) {
                if (!PaymentStatusEnum.BALANCE.getValue().equals(item.getPaymentStatus())) {
                    socialNum += 1;
                }
                socialPaySum = socialPaySum.add(new BigDecimal(item.getSocialSum()));
            }
        }
        dto.setSocialNum(socialNum);
        dto.setSocialPaySum(socialPaySum.toPlainString());
    }

    /**
     * 查询台账id是否已经薪资核算核算过
     *
     * @param param
     * @return
     */
    public int checkIfBusinessAccounting(InsuranceAccountBatchPO param) {
        List<SIAccountUtilDTO> list = getSIAccountUtilMapper().checkIfBusinessaccounting(param.getId());
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        return (int) list.stream().filter( f -> {
            String billMonthBySob = sdf.format(convertSalaryMonthToBillMonth(f.getSalaryMonth(), f.getSocialSecurityCycleType()));
            return f.getBillmonth().equals(billMonthBySob.substring(0, 7));
        }).count();
    }

    public Date convertSalaryMonthToBillMonth(Date salaryMonth, Integer socialSecurityCycleType) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(salaryMonth);
        calendar.add(Calendar.MONTH, socialSecurityCycleType - 3);
        return calendar.getTime();
    }

    /**
     * 更新薪资台账
     *
     * @param param
     * @return
     */
    public void updateById(InsuranceAccountBatchPO param) {
        getInsuranceAccountBatchMapper().updateById(param);
    }

    /**
     * 更新福利台账
     */
    public void updateByEmployeeIdAndBillMonth(InsuranceAccountDetailPO insuranceAccountDetailPO) {
        getInsuranceAccountDetailMapper().updateByEmployeeIdAndBillMonth(insuranceAccountDetailPO);
    }

    /*****以上代码为SIAccountBiz中方法逻辑迁移，旨在减少Biz类的使用*****/

}
