package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.base.bu3;

import cn.estsh.i3plus.ext.mes.api.base.IModuleExcelManageService;
import cn.estsh.i3plus.ext.mes.api.base.IProdOrgExtService;
import cn.estsh.i3plus.ext.mes.api.base.bu.IBusiConfigService;
import cn.estsh.i3plus.ext.mes.api.base.bu3.ISxAssistOutAndEnterService;
import cn.estsh.i3plus.ext.mes.api.base.bu3.ISxPartCategoryPlanRateService;
import cn.estsh.i3plus.ext.mes.apiservice.util.FileExtUtil;
import cn.estsh.i3plus.ext.mes.apiservice.util.SxExcelExtUtil;
import cn.estsh.i3plus.ext.mes.icloud.sdk.ICoreSysPushMessageCloud;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesAssistOutAndEnter;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesBusiConfig;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesPartCategoryPlanRate;
import cn.estsh.i3plus.ext.mes.pojo.bean.MesWorkCenterExt;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.SxAssistOutAndEnterModel;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.SxAssistOutAndEnterPushDingInfoModel;
import cn.estsh.i3plus.ext.mes.pojo.model.bu3.SxAssistOutAndEnterReportModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesAssistOutAndEnterRepository;
import cn.estsh.i3plus.ext.mes.pojo.repository.MesBusiConfigRepository;
import cn.estsh.i3plus.ext.mes.pojo.sqlpack.MesExtHqlPack;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.platform.common.convert.ConvertBean;
import cn.estsh.i3plus.platform.common.exception.ImppExceptionEnum;
import cn.estsh.i3plus.platform.common.tool.MathOperation;
import cn.estsh.i3plus.platform.common.tool.TimeTool;
import cn.estsh.i3plus.pojo.base.bean.DdlPackBean;
import cn.estsh.i3plus.pojo.base.bean.ListPager;
import cn.estsh.i3plus.pojo.base.codemaker.SnowflakeIdMaker;
import cn.estsh.i3plus.pojo.base.common.Pager;
import cn.estsh.i3plus.pojo.base.common.PagerHelper;
import cn.estsh.i3plus.pojo.base.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesFile;
import cn.estsh.i3plus.pojo.model.platform.PushDataNotifyModel;
import cn.estsh.i3plus.pojo.platform.bean.SysFile;
import cn.estsh.impp.framework.boot.auth.AuthUtil;
import cn.estsh.impp.framework.boot.exception.ImppBusiException;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import cn.estsh.impp.framework.boot.fileservice.ImppFileService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.poi.openxml4j.util.ZipSecureFile;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangjie
 * @version 1.0
 * @date 2021/1/13 9:28
 **/
@Slf4j
@Service
public class SxAssistOutAndEnterService implements ISxAssistOutAndEnterService {

    @Autowired
    private MesAssistOutAndEnterRepository assistOutAndEnterRepository;

    @Autowired
    private IBusiConfigService busiConfigService;

    @Autowired
    private IProdOrgExtService prodOrgExtService;

    @Autowired
    private ISxPartCategoryPlanRateService partCategoryPlanRateService;

    @Autowired
    private IModuleExcelManageService moduleExcelManageService;

    @Autowired
    private SnowflakeIdMaker snowflakeIdMaker;

    @Autowired
    private ImppFileService imppFileService;

    @Autowired
    private ICoreSysPushMessageCloud pushMessageCloud;

    @Autowired
    private MesBusiConfigRepository busiConfigRepository;

    private final static String SX_ASSIST_OUT_AND_ENTER_REPORT = "SX_ASSIST_OUT_AND_ENTER_REPORT";
    private final static Integer TEMPLATE_LAST_ROW = 6;

    @Override
    public ListPager<SxAssistOutAndEnterModel> queryAssistOutAndEnterByPager(SxAssistOutAndEnterModel assistOutAndEnter, Pager pager) {
        List<SxAssistOutAndEnterModel> resultList = new ArrayList<>();
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnter(assistOutAndEnter, true);
        pager = PagerHelper.getPager(pager, assistOutAndEnterRepository.findByHqlWhereCount(packBean));
        packBean.setOrderByStr(" order by createDatetime Desc ");
        List<MesAssistOutAndEnter> resultDbList = assistOutAndEnterRepository.findByHqlWherePage(packBean, pager);
        if (!CollectionUtils.isEmpty(resultDbList)) {
            Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(assistOutAndEnter.getOrganizeCode(), MesExtConstWords.OWNER_DEPARTMENT_CFG);
            packResultList(assistOutAndEnter.getOrganizeCode(), resultList, resultDbList, ownerDepartmentMap);
        }
        return new ListPager(resultList, pager);
    }

    @Override
    public void packResultList(String organizeCode, List<SxAssistOutAndEnterModel> resultList, List<MesAssistOutAndEnter> resultDbList) {
        if (CollectionUtils.isEmpty(resultDbList)) return;
        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(organizeCode, MesExtConstWords.OWNER_DEPARTMENT_CFG);
        packResultList(organizeCode, resultList, resultDbList, ownerDepartmentMap);
    }

    private void packResultList(String organizeCode, List<SxAssistOutAndEnterModel> resultList, List<MesAssistOutAndEnter> resultDbList, Map<String, String> ownerDepartmentMap) {

        Map<String, String> careerMap = busiConfigService.getConfigMap(organizeCode, MesExtConstWords.SX_CAREER_CFG);
        Map<String, String> categoryMap = partCategoryPlanRateService.getCategoryMap(organizeCode);

        for (MesAssistOutAndEnter item : resultDbList) {
            if (null == item) continue;
            SxAssistOutAndEnterModel result = new SxAssistOutAndEnterModel();
            BeanUtils.copyProperties(item, result);
            result.setIdStr(item.getId().toString());
            result.setAssistOutAndEnterDetailName(StringUtils.isEmpty(result.getAssistOutAndEnterDetail()) ? null :
                    MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.valueOfDescription(result.getAssistOutAndEnterDetail()));
            result.setOwnerDepartmentName((!StringUtils.isEmpty(result.getOwnerDepartment()) && !CollectionUtils.isEmpty(ownerDepartmentMap) &&
                    ownerDepartmentMap.containsKey(result.getOwnerDepartment())) ? ownerDepartmentMap.get(result.getOwnerDepartment()) : null);
            result.setCareerName((!StringUtils.isEmpty(result.getCareerCode()) && !CollectionUtils.isEmpty(careerMap) &&
                    careerMap.containsKey(result.getCareerCode())) ? careerMap.get(result.getCareerCode()) : null);
            result.setCategoryName((!StringUtils.isEmpty(result.getCategoryCode()) && !CollectionUtils.isEmpty(categoryMap) &&
                    categoryMap.containsKey(result.getCategoryCode())) ? categoryMap.get(result.getCategoryCode()) : null);
            result.setLiabilityAttribution(result.getLiabilityAttribution()==null? 0 : result.getLiabilityAttribution());
            resultList.add(result);
        }
    }

    @Override
    public void insertAssistOutAndEnter(MesAssistOutAndEnter assistOutAndEnter) {
        checkData(assistOutAndEnter.getStartTime(), assistOutAndEnter.getEndTime(), assistOutAndEnter.getInfluenceNumber());
        assistOutAndEnter.setIntervalTime(getIntervalTime(assistOutAndEnter.getStartTime(), assistOutAndEnter.getEndTime()));
        assistOutAndEnter.setInfluenceTime(calcMul(assistOutAndEnter.getIntervalTime(), assistOutAndEnter.getInfluenceNumber()));
        assistOutAndEnter.setPersonnelCost(getPersonnelCost(assistOutAndEnter, assistOutAndEnter.getOrganizeCode(), assistOutAndEnter.getWorkCenterCode()));
        assistOutAndEnter.setAmount(calcMul(assistOutAndEnter.getInfluenceTime(), assistOutAndEnter.getPersonnelCost()));
        assistOutAndEnter.setInfluenceDate(assistOutAndEnter.getStartTime().substring(0, 10));
        assistOutAndEnter.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        ConvertBean.serviceModelInitialize(assistOutAndEnter, assistOutAndEnter.getCreateUser());
        assistOutAndEnterRepository.insert(assistOutAndEnter);
        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(assistOutAndEnter.getOrganizeCode(), MesExtConstWords.OWNER_DEPARTMENT_CFG);
        pushMessageCloud.pushMessage(this.getAssistOutAndEnterDingPushInfo(assistOutAndEnter,null,ownerDepartmentMap == null ? new HashMap<>() : ownerDepartmentMap));
    }

    private void checkData(String startTime, String endTime, Integer influenceNumber) {
        if (!TimeTool.checkDateFormat(startTime, MesExtConstWords.DATETIME_FORMAT) || !TimeTool.checkDateFormat(startTime, MesExtConstWords.DATETIME_FORMAT))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("开始时间[%s]或结束时间[%s]格式错误,请检查时间格式[yyyy-MM-dd HH:mm:00]", startTime, endTime)
                    .build();
        if (!startTime.substring(16, 19).equals(MesExtConstWords.APPEND_SECONDS) || !endTime.substring(16, 19).equals(MesExtConstWords.APPEND_SECONDS))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("开始时间[%s]或结束时间[%s]格式错误,请检查时间格式[yyyy-MM-dd HH:mm:00]", startTime, endTime)
                    .build();
        if (startTime.compareTo(endTime) >= 0)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("开始时间[%s]必须小于结束时间[%s]", startTime, endTime)
                    .build();
        if (influenceNumber.compareTo(0) < 0)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("影响人数[%s]必须大于等于0", influenceNumber)
                    .build();
    }

    private Double getIntervalTime(String startTime, String endTime) {
        try {
            return new Double(TimeTool.getSecoundsBetweenTime(2, startTime, endTime));
        } catch (ParseException e) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("根据开始时间[%s]结束时间[%s]计算影响时间发生异常:%s", startTime, endTime, e.getMessage())
                    .build();
        }
    }

    private String getPersonnelCost(MesAssistOutAndEnter assistOutAndEnter, String organizeCode, String workCenterCode) {
        MesWorkCenterExt workCenterExt = prodOrgExtService.getWorkCenterExt(organizeCode, workCenterCode);
        if (null == workCenterExt)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线信息[%s]不存在", workCenterCode)
                    .build();
        if (StringUtils.isEmpty(workCenterExt.getCategoryCode()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线信息[%s]未配置产品别", workCenterCode)
                    .build();
        if (StringUtils.isEmpty(workCenterExt.getCareerCode()))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("生产线信息[%s]未配置事业别", workCenterCode)
                    .build();
        if (!StringUtils.isEmpty(workCenterExt.getPersonnelCost())) {
            try {
                Double.parseDouble(workCenterExt.getPersonnelCost());
            } catch (NumberFormatException e) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生产线信息[%s]配置的人件费[%s]数据异常", workCenterCode, workCenterExt.getPersonnelCost())
                        .build();
            }
        }
        assistOutAndEnter.setCategoryCode(workCenterExt.getCategoryCode());
        assistOutAndEnter.setCareerCode(workCenterExt.getCareerCode());
        return workCenterExt.getPersonnelCost();
    }

    private Double calcMul(Double d, Object o) {
        return StringUtils.isEmpty(o) ? new Double(0) : MathOperation.mul(d, new Double(o.toString()));
    }

    @Override
    public MesAssistOutAndEnter updateAssistOutAndEnter(SxAssistOutAndEnterModel assistOutAndEnter) {
        MesAssistOutAndEnter assistOutAndEnterDb = getAssistOutAndEnterByIdStr(assistOutAndEnter.getIdStr(), true,MesExtEnumUtil.ASSIST_OUT_AND_ENTER_CONFIRM_LEVEL.TAKE_ON.getValue());
        checkData(assistOutAndEnter.getStartTime(), assistOutAndEnter.getEndTime(), assistOutAndEnter.getInfluenceNumber());
        Double intervalTime = getIntervalTime(assistOutAndEnter.getStartTime(), assistOutAndEnter.getEndTime());
        Double influenceTime = calcMul(intervalTime, assistOutAndEnter.getInfluenceNumber());
        String personnelCost = getPersonnelCost(assistOutAndEnterDb, assistOutAndEnter.getOrganizeCode(), assistOutAndEnter.getWorkCenterCode());
        assistOutAndEnterDb.setAmount(calcMul(influenceTime, personnelCost));
        assistOutAndEnterDb.setPersonnelCost(personnelCost);
        assistOutAndEnterDb.setIntervalTime(intervalTime);
        assistOutAndEnterDb.setInfluenceTime(influenceTime);
        assistOutAndEnterDb.setWorkCenterCode(assistOutAndEnter.getWorkCenterCode());
        assistOutAndEnterDb.setWorkCenterName(assistOutAndEnter.getWorkCenterName());
        assistOutAndEnterDb.setAssistOutAndEnterDetail(assistOutAndEnter.getAssistOutAndEnterDetail());
        assistOutAndEnterDb.setOwnerDepartment(assistOutAndEnter.getOwnerDepartment());
        assistOutAndEnterDb.setWorkContent(assistOutAndEnter.getWorkContent());
        assistOutAndEnterDb.setStartTime(assistOutAndEnter.getStartTime());
        assistOutAndEnterDb.setEndTime(assistOutAndEnter.getEndTime());
        assistOutAndEnterDb.setInfluenceNumber(assistOutAndEnter.getInfluenceNumber());
        assistOutAndEnterDb.setInfluenceDate(assistOutAndEnterDb.getStartTime().substring(0, 10));
        assistOutAndEnterDb.setCooperation(assistOutAndEnter.getCooperation());
        assistOutAndEnterDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
        assistOutAndEnterDb.setTakeOn(assistOutAndEnter.getTakeOn());
        assistOutAndEnterDb.setTakeOnUserName(assistOutAndEnter.getTakeOnUserName());
        assistOutAndEnterDb.setPersonResponsible(assistOutAndEnter.getPersonResponsible());
        assistOutAndEnterDb.setPersonResponsibleUserName(assistOutAndEnter.getPersonResponsibleUserName());
        assistOutAndEnterDb.setResponsibleMinister(assistOutAndEnter.getResponsibleMinister());
        assistOutAndEnterDb.setResponsibleMinisterUserName(assistOutAndEnter.getResponsibleMinisterUserName());
        ConvertBean.serviceModelUpdate(assistOutAndEnterDb, assistOutAndEnter.getModifyUser());
        return assistOutAndEnterRepository.save(assistOutAndEnterDb);
    }

    @Override
    public void updateAssistOutAndEnterValidById(String[] idStrArr, Integer status, String userName) {
        if (status != CommonEnumUtil.IS_VAILD.INVAILD.getValue() && status != CommonEnumUtil.IS_VAILD.VAILD.getValue()) {
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("启用，禁用枚举状态值[%s]未被定义", status)
                    .build();
        }

        List<MesAssistOutAndEnter> assistOutAndEnterDbList = getAssistOutAndEnterListByIdStrArr(idStrArr, false);

        if (CollectionUtils.isEmpty(assistOutAndEnterDbList)) return;

        for (MesAssistOutAndEnter assistOutAndEnterDb : assistOutAndEnterDbList) {
            if (null == assistOutAndEnterDb) continue;
            assistOutAndEnterDb.setIsValid(status);
            assistOutAndEnterDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(assistOutAndEnterDb, userName);
            assistOutAndEnterRepository.save(assistOutAndEnterDb);
        }

    }

    @Override
    public void deleteAssistOutAndEnterById(String[] idStrArr, String userName) {

        List<MesAssistOutAndEnter> assistOutAndEnterDbList = getAssistOutAndEnterListByIdStrArr(idStrArr, false);

        if (CollectionUtils.isEmpty(assistOutAndEnterDbList)) return;

        for (MesAssistOutAndEnter assistOutAndEnterDb : assistOutAndEnterDbList) {
            if (null == assistOutAndEnterDb) continue;
            assistOutAndEnterDb.setIsDeleted(CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue());
            assistOutAndEnterDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(assistOutAndEnterDb, userName);
            assistOutAndEnterRepository.save(assistOutAndEnterDb);
        }

    }

    @Override
    public void doConfirmAssistOutAndEnterById(String[] idStrArr, String organizeCode, String userName, String userLoginName,int level,Integer liabilityAttribution) {

        List<MesAssistOutAndEnter> assistOutAndEnterDbList = getAssistOutAndEnterListByIdStrArr2Confirm(idStrArr, organizeCode, userLoginName,level);

        if (CollectionUtils.isEmpty(assistOutAndEnterDbList)) return;

        liabilityAttribution = liabilityAttribution == null ? 10 : liabilityAttribution;
        doConfirmAssistOutAndEnterList(userName, assistOutAndEnterDbList,level,liabilityAttribution);
        if (level != MesExtEnumUtil.ASSIST_OUT_AND_ENTER_CONFIRM_LEVEL.TAKE_ON.getValue()) return;
        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(organizeCode, MesExtConstWords.OWNER_DEPARTMENT_CFG);
        assistOutAndEnterDbList.forEach(o -> pushMessageCloud.pushMessage(this.getAssistOutAndEnterDingPushInfo(o,level,ownerDepartmentMap == null ? new HashMap<>() : ownerDepartmentMap)));
    }

    private List<MesAssistOutAndEnter> getAssistOutAndEnterListByIdStrArr2Confirm(String[] idStrArr, String organizeCode, String userLoginName,int level) {
        List<MesAssistOutAndEnter> assistOutAndEnterDbList = null;
        for (String idStr : idStrArr) {
            if (StringUtils.isEmpty(idStr)) continue;
            MesAssistOutAndEnter assistOutAndEnterDb = getAssistOutAndEnterByIdStr(idStr, true,level);
            checkConfirmAuth(organizeCode, userLoginName, level, idStr, assistOutAndEnterDb);
            if (CollectionUtils.isEmpty(assistOutAndEnterDbList)) assistOutAndEnterDbList = new ArrayList<>();
            assistOutAndEnterDbList.add(assistOutAndEnterDb);
        }
        return assistOutAndEnterDbList;
    }

    private static void checkConfirmAuth(String organizeCode, String userLoginName, int level, String idStr, MesAssistOutAndEnter assistOutAndEnterDb) {
        List<String> confirmPeopleList = null;
        switch (level){
            case 10:
                confirmPeopleList = Arrays.asList(assistOutAndEnterDb.getTakeOn().split(","));
                break;
            case 20:
                confirmPeopleList = Arrays.asList(assistOutAndEnterDb.getPersonResponsible().split(","));
                break;
            case 30:
                confirmPeopleList = Arrays.asList(assistOutAndEnterDb.getResponsibleMinister().split(","));
                break;
        }
        assert confirmPeopleList != null;
        if (!confirmPeopleList.contains(userLoginName))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("工厂[%s]当前确认的援入援出明细项的为[%s],确认人为[%s]当前账号[%s]无该按钮的确认权限", organizeCode, idStr, confirmPeopleList.toString(), userLoginName)
                    .build();
    }

    private Boolean checkConfirmAuth(String organizeCode, String userLoginName, String ownerDepartment) {
        Map<String, String> ownerDepartmentAuthMap = busiConfigService.getConfigMap(organizeCode, MesExtConstWords.OWNER_DEPARTMENT_AUTH_CFG);
        String auth = CollectionUtils.isEmpty(ownerDepartmentAuthMap) ? null : ownerDepartmentAuthMap.get(ownerDepartment);
        List<String> authList = StringUtils.isEmpty(auth) ? null : Arrays.asList(auth.split(MesExtConstWords.COMMA));
        if (CollectionUtils.isEmpty(authList) || !authList.contains(userLoginName)) return false;
        return true;
    }

    private void doConfirmAssistOutAndEnterList(String userName, List<MesAssistOutAndEnter> assistOutAndEnterDbList,int level,int liabilityAttribution) {
        for (MesAssistOutAndEnter assistOutAndEnterDb : assistOutAndEnterDbList) {
            if (null == assistOutAndEnterDb) continue;
            assistOutAndEnterDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(assistOutAndEnterDb, userName);
            switch (level){
                case 10:
                    assistOutAndEnterDb.setTakeOnConfirm(userName);
                    assistOutAndEnterDb.setTakeOnConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                    assistOutAndEnterDb.setLiabilityAttribution(liabilityAttribution);
                    break;
                case 20:
                    assistOutAndEnterDb.setPersonResponsibleConfirm(userName);
                    assistOutAndEnterDb.setPersonResponsibleConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                    break;
                case 30:
                    assistOutAndEnterDb.setResponsibleMinisterConfirm(userName);
                    assistOutAndEnterDb.setResponsibleMinisterConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                    break;
            }
            assistOutAndEnterRepository.save(assistOutAndEnterDb);
        }
    }

    private void doJobConfirmAssistOutAndEnterList(List<MesAssistOutAndEnter> assistOutAndEnterDbList,int level,int liabilityAttribution) {
        for (MesAssistOutAndEnter assistOutAndEnterDb : assistOutAndEnterDbList) {
            if (null == assistOutAndEnterDb) continue;
            assistOutAndEnterDb.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(assistOutAndEnterDb, MesExtConstWords.JOB);
            switch (level){
                case 10:
                case 20:
                    if (StringUtils.isEmpty(assistOutAndEnterDb.getTakeOnConfirm())){
                        assistOutAndEnterDb.setTakeOnConfirm(getConfirmUserNameAppendJob(assistOutAndEnterDb.getTakeOnUserName()));
                        assistOutAndEnterDb.setTakeOnConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                        assistOutAndEnterDb.setLiabilityAttribution(liabilityAttribution);
                    }
                    assistOutAndEnterDb.setPersonResponsibleConfirm(getConfirmUserNameAppendJob(assistOutAndEnterDb.getPersonResponsibleUserName()));
                    assistOutAndEnterDb.setPersonResponsibleConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                    break;
                case 30:
                    assistOutAndEnterDb.setResponsibleMinisterConfirm(getConfirmUserNameAppendJob(assistOutAndEnterDb.getResponsibleMinisterUserName()));
                    assistOutAndEnterDb.setResponsibleMinisterConfirmTime(assistOutAndEnterDb.getModifyDatetime());
                    break;
            }
            assistOutAndEnterRepository.update(assistOutAndEnterDb);
        }
    }

    private String getConfirmUserNameAppendJob(String takeOn) {
        if (StringUtils.isEmpty(takeOn)) return "";
        StringBuilder resultConfirmNames = new StringBuilder();
        for (String confirmName : takeOn.split(",")) {
            resultConfirmNames.append(confirmName).append("-").append(MesExtConstWords.JOB).append(",");
        }
        return resultConfirmNames.substring(0,resultConfirmNames.length()-1);
    }

    private List<MesAssistOutAndEnter> getAssistOutAndEnterListByIdStrArr(String[] idStrArr, Boolean isCheckConfirm) {
        List<MesAssistOutAndEnter> assistOutAndEnterDbList = null;
        for (String idStr : idStrArr) {
            if (StringUtils.isEmpty(idStr)) continue;
            MesAssistOutAndEnter assistOutAndEnterDb = getAssistOutAndEnterByIdStr(idStr, isCheckConfirm,MesExtEnumUtil.ASSIST_OUT_AND_ENTER_CONFIRM_LEVEL.TAKE_ON.getValue());
            if (CollectionUtils.isEmpty(assistOutAndEnterDbList)) assistOutAndEnterDbList = new ArrayList<>();
            assistOutAndEnterDbList.add(assistOutAndEnterDb);
        }
        return assistOutAndEnterDbList;
    }

    private MesAssistOutAndEnter getAssistOutAndEnterByIdStr(String idStr, Boolean isCheckConfirm,Integer level) {
        MesAssistOutAndEnter assistOutAndEnterDb = assistOutAndEnterRepository.getById(Long.parseLong(idStr));
        if (null == assistOutAndEnterDb)
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                    .setErrorDetail("援入援出明细记录ID[%s]记录不存在", idStr)
                    .build();
        if (isCheckConfirm) checkWhetherConfirm(idStr, level, assistOutAndEnterDb);
        return assistOutAndEnterDb;
    }

    private static void checkWhetherConfirm(String idStr, Integer level, MesAssistOutAndEnter assistOutAndEnterDb) {
        // 对应枚举 MesExtEnumUtil.ASSIST_OUT_AND_ENTER_CONFIRM_LEVEL
        switch (level) {
            case 10 :
                if (!StringUtils.isEmpty(assistOutAndEnterDb.getTakeOnConfirm()))
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录已于[%s]被[%s]担当确认,操作失败", idStr, assistOutAndEnterDb.getTakeOnConfirmTime(), assistOutAndEnterDb.getTakeOnConfirm())
                            .build();
                break;
            case 20 :
                if (StringUtils.isEmpty(assistOutAndEnterDb.getTakeOnConfirm())){
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录还未进行担当确认,操作失败", idStr)
                            .build();
                }else if (!StringUtils.isEmpty(assistOutAndEnterDb.getPersonResponsibleConfirm())){
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录已于[%s]被[%s]责任人确认,操作失败", idStr, assistOutAndEnterDb.getPersonResponsibleConfirmTime(), assistOutAndEnterDb.getPersonResponsibleConfirm())
                            .build();
                }
                break;
            case 30 :
                if (StringUtils.isEmpty(assistOutAndEnterDb.getTakeOnConfirm())){
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录还未进行担当确认,操作失败", idStr)
                            .build();
                }else if (StringUtils.isEmpty(assistOutAndEnterDb.getPersonResponsibleConfirm())){
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录还未进行责任人确认,操作失败", idStr)
                            .build();
                }else if(!StringUtils.isEmpty(assistOutAndEnterDb.getResponsibleMinisterConfirm())){
                    throw ImppExceptionBuilder.newInstance()
                            .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                            .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION_DATA_NOT_EXIT.getCode())
                            .setErrorDetail("援入援出明细记录ID[%s]记录已于[%s]被[%s]责任部长确认,操作失败", idStr, assistOutAndEnterDb.getResponsibleMinisterConfirmTime(), assistOutAndEnterDb.getResponsibleMinisterConfirm())
                            .build();
                }
                break;
        }
    }

    @Override
    public SxAssistOutAndEnterReportModel doAssistOutAndEnterReport(SxAssistOutAndEnterReportModel data) {

        calcDateTime(data);

        List<MesAssistOutAndEnter> dataList = getAssistOutAndEnterReportDataList(data);

        if (CollectionUtils.isEmpty(dataList)) return null;

        initDataFieldAndTitle(data);

        handleTableData(data, dataList);

        handleLineY(data, dataList);

        handlePieData(data);

        return data;
    }

    private void calcDateTime(SxAssistOutAndEnterReportModel data) {
        data.setInfluenceDateStart(data.getStartTime() + MesExtConstWords.DATE_DD_01);
        data.setInfluenceDateEnd(TimeTool.timeCalc(TimeTool.stringParseToDate(data.getEndTime(), MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, 1, MesExtConstWords.DATE_FORMAT_YM) + MesExtConstWords.DATE_DD_01);
    }

    private List<MesAssistOutAndEnter> getAssistOutAndEnterReportDataList(SxAssistOutAndEnterReportModel data) {
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnter(
                new SxAssistOutAndEnterModel(data.getOrganizeCode(), data.getCategoryCode(), data.getCareerCode(),
                        data.getAssistOutAndEnterDetail(), data.getInfluenceDateStart(), data.getInfluenceDateEnd(),true).liabilityAttribution(data.getLiabilityAttribution()), false);
        List<MesAssistOutAndEnter> dataList = assistOutAndEnterRepository.findByHqlWhere(packBean);
        dataList = filterDataList(dataList);
        if (CollectionUtils.isEmpty(dataList)) return null;
        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(data.getOrganizeCode(), MesExtConstWords.OWNER_DEPARTMENT_CFG);
        if (CollectionUtils.isEmpty(data.ownerDepartmentMap(ownerDepartmentMap))) return null;
        return filterDataListByDepAndCenter(data.getWorkCenterCodeArr(), data.getOwnerDepartmentArr(), data.getOwnerDepartmentMap(), dataList);
    }

    private List<MesAssistOutAndEnter> filterDataList(List<MesAssistOutAndEnter> dataList) {
        dataList = CollectionUtils.isEmpty(dataList) ? null : dataList.stream().filter(o -> (null != o &&
                MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue() != o.getAssistOutAndEnterDetail())).collect(Collectors.toList());
        return dataList;
    }

    private List<MesAssistOutAndEnter> filterDataListByDepAndCenter(String workCenterCodeArr, String ownerDepartmentArr, Map<String, String> ownerDepartmentMap, List<MesAssistOutAndEnter> dataList) {
        if (!StringUtils.isEmpty(workCenterCodeArr)) {
            List<String> workCenterCodeList = Arrays.asList(workCenterCodeArr.split(MesExtConstWords.COMMA));
            dataList = dataList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getWorkCenterCode()) && workCenterCodeList.contains(o.getWorkCenterCode()))).collect(Collectors.toList());
        }
        if (!CollectionUtils.isEmpty(dataList)) {
            List<String> ownerDepartmentList = !StringUtils.isEmpty(ownerDepartmentArr) ?
                    Arrays.asList(ownerDepartmentArr.split(MesExtConstWords.COMMA)) : ownerDepartmentMap.keySet().stream().collect(Collectors.toList());
            dataList = dataList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getOwnerDepartment()) && ownerDepartmentList.contains(o.getOwnerDepartment()))).collect(Collectors.toList());
        }
        return dataList;
    }

    private void initDataFieldAndTitle(SxAssistOutAndEnterReportModel data) {

        String[] start = data.getStartTime().split(MesExtConstWords.E_LINE);
        String[] end = data.getEndTime().split(MesExtConstWords.E_LINE);

        data.title(data.getStartTime().equals(data.getEndTime())
                ? String.format("%s年%s月支援时间汇总", start[0], start[1])
                : String.format("%s年%s月-%s年%s月支援时间汇总", start[0], start[1], end[0], end[1])
        ).addTableName("index", "序号").addTableName("ownerDepartmentName", "责任区分");

        if (Integer.valueOf(start[1]).compareTo(Integer.valueOf(end[1])) > 0) {
            initDataField4Date(data, Integer.valueOf(start[1]), 12, start[0]);
            initDataField4Date(data, 1, Integer.valueOf(end[1]), end[0]);
        } else {
            initDataField4Date(data, Integer.valueOf(start[1]), Integer.valueOf(end[1]), start[0]);
        }

        data.addTableName("amountDate", "合计时间").addTableName("amountRatePercent", "合计占比").addTableName("amount", "合计金额");

    }

    private void initDataField4Date(SxAssistOutAndEnterReportModel data, Integer start, Integer end, String year) {
        for (int i = start; i <= end; i ++) {
            data.addTableName(String.format("month%s", i), String.format("%s月", i))
                    .addLineX(String.valueOf(i))
                    .addMonth(String.format("%s-%s", year, i < 10 ? MesExtConstWords.ZERO_STR + i : String.valueOf(i)));
        }
    }

    private void handleTableData(SxAssistOutAndEnterReportModel data, List<MesAssistOutAndEnter> dataList) {

        Double amountDate = getAmountDate(dataList);

        Map<String, List<MesAssistOutAndEnter>> dataMap = dataList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesAssistOutAndEnter::getOwnerDepartment));

        for (Map.Entry<String, List<MesAssistOutAndEnter>> entry : dataMap.entrySet()) {
            if (null == entry) continue;
            Map<String, Object> tableData = new HashMap<>();
            tableData.put("ownerDepartment", entry.getKey());
            tableData.put("ownerDepartmentName", data.getOwnerDepartmentMap().get(entry.getKey()));
            tableData.put("amountDate", getAmountDate(entry.getValue()));

            Map<String, List<MesAssistOutAndEnter>> dataMapByMonth = entry.getValue().stream().filter(o -> null != o).collect(Collectors.groupingBy(o -> o.getInfluenceDate().substring(0, 7)));
            for (String month : data.getMonthList()) {
                if (StringUtils.isEmpty(month)) continue;
                Double amountMonth = getAmountDate(dataMapByMonth.get(month));
                tableData.put(String.format("month%s", Integer.valueOf(month.substring(5, 7))), amountMonth + "（" + formatPercent(MathOperation.div(amountMonth, amountDate)) + "）");
            }

            tableData.put("amountRate", MathOperation.compareTo(amountDate, new Double(0)) == 0 ?
                    new Double(0) : MathOperation.div((Double) tableData.get("amountDate"), amountDate));
            tableData.put("amountRatePercent", formatPercent((Double) tableData.get("amountRate")));
            tableData.put("amount", getAmount(entry.getValue()));

            data.addTableData(tableData);
        }

        data.setTableDataList(data.getTableDataList().stream().filter(o -> null != o)
                .sorted(Comparator.comparing(SxAssistOutAndEnterService::comparingByAmountRate).reversed()).collect(Collectors.toList()));

        Integer index = 1;
        for (Map<String, Object> tableData : data.getTableDataList()) {
            if (null == tableData) continue;
            tableData.put("index", index);
            index ++;
        }

    }

    private void handleLineY(SxAssistOutAndEnterReportModel data, List<MesAssistOutAndEnter> dataList) {
        Map<String, List<MesAssistOutAndEnter>> dataMapByMonth = dataList.stream().filter(o -> null != o).collect(Collectors.groupingBy(o -> o.getInfluenceDate().substring(0, 7)));
        for (String month : data.getMonthList()) {
            if (StringUtils.isEmpty(month)) continue;
            data.addLineY(getAmount(dataMapByMonth.get(month)));
        }
    }

    private void handlePieData(SxAssistOutAndEnterReportModel data) {
        for (Map<String, Object> tableData : data.getTableDataList()) {
            if (null == tableData) continue;
            data.addPieData((String) tableData.get("ownerDepartmentName"), (Double) tableData.get("amountDate"), (String) tableData.get("amountRatePercent"));
        }
    }

    private Double getAmountDate(List<MesAssistOutAndEnter> dataList) {
        return CollectionUtils.isEmpty(dataList) ? new Double(0) :
                dataList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getInfluenceTime()))).mapToDouble(MesAssistOutAndEnter::getInfluenceTime).sum();
    }

    private Double getAmount(List<MesAssistOutAndEnter> dataList) {
        return CollectionUtils.isEmpty(dataList) ? new Double(0) :
                dataList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAmount()))).mapToDouble(MesAssistOutAndEnter::getAmount).sum();
    }

    private String formatPoint(Double value) { return String.format("%.4f", value); }

    private String formatPercent(Double value) {
        return MathOperation.mul(new Double(formatPoint(value)), 100) + MesExtConstWords.PERCENT;
    }

    private static Double comparingByAmountRate(Map<String, Object> map) {
        return (Double) map.get("amountDate");
    }

    @Override
    public List<SxAssistOutAndEnterModel> queryAssistOutAndEnterReportDetailList(SxAssistOutAndEnterModel model) {
        model.setTakeOnConfirmBool(true);
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnter(model, true);

        List<MesAssistOutAndEnter> dataList = assistOutAndEnterRepository.findByHqlWhere(packBean);

        dataList = filterDataList(dataList);

        if (CollectionUtils.isEmpty(dataList)) return null;

        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(model.getOrganizeCode(), MesExtConstWords.OWNER_DEPARTMENT_CFG);

        if (CollectionUtils.isEmpty(ownerDepartmentMap)) return null;

        dataList = filterDataListByDepAndCenter(model.getWorkCenterCodeArr(), model.getOwnerDepartmentArr(), ownerDepartmentMap, dataList);

        List<SxAssistOutAndEnterModel> resultList = new ArrayList<>();

        packResultList(model.getOrganizeCode(), resultList, dataList, ownerDepartmentMap);

        return resultList;
    }

    @Override
    public void doDownLoadAssistOutAndEnterReport(HttpServletResponse resp, SxAssistOutAndEnterReportModel data) {

        calcDateTime(data);

        List<MesAssistOutAndEnter> dataList = getAssistOutAndEnterReportDataList(data);

        checkData4DownLoad(dataList);

        MesFile fileDb = moduleExcelManageService.getTemplateFile(data.getOrganizeCode(), SX_ASSIST_OUT_AND_ENTER_REPORT);

        File fileTemplate = null;
        File excelFile = null;
        String excelName = null;
        FileOutputStream fos = null;

        try {

            InputStream inputStream = FileExtUtil.getInputStream(fileDb.getFileUrl());
            if(inputStream == null)
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.IO_EXCEPTION_FILE.getCode())
                        .setErrorDetail("导出模板[%s]对应的文件URL[%s]获取文件流异常", SX_ASSIST_OUT_AND_ENTER_REPORT, fileDb.getFileUrl())
                        .build();

            List<SxAssistOutAndEnterModel> resultList = overrideDataList(data, dataList);

            fileTemplate= File.createTempFile(String.valueOf(snowflakeIdMaker.nextId()), MesExtConstWords.DECIMAL_POINT_STR + fileDb.getFileType().replaceAll(String.valueOf((char)160), MesExtConstWords.EMPTY).trim());
            FileUtils.copyInputStreamToFile(inputStream, fileTemplate);

            Workbook workbook = SxExcelExtUtil.getWorkbook(fileTemplate);

            Sheet sheet = workbook.getSheetAt(MesExtConstWords.ZERO);

            SxExcelExtUtil.copyRow(workbook, sheet, TEMPLATE_LAST_ROW, TEMPLATE_LAST_ROW + 1, resultList.size() - 1, true, null);

            setCellValue4ResultList(sheet, resultList);

            fos = new FileOutputStream(fileTemplate);
            workbook.write(fos);
            fos.flush();

            //获取导出文件名称
            excelName = getExcelTitle(data, resultList);

            //根据模板写入文件
            excelFile= File.createTempFile(excelName, MesExtConstWords.DECIMAL_POINT_STR + fileDb.getFileType().replaceAll(String.valueOf((char)160), MesExtConstWords.EMPTY).trim());

            OutputStream out = new FileOutputStream(excelFile);
            BufferedOutputStream bos = new BufferedOutputStream(out);
            ZipSecureFile.setMinInflateRatio(-1.0d);
            ExcelWriter excelWriter = EasyExcel.write(bos).withTemplate(fileTemplate).build();
            WriteSheet writeSheet = EasyExcel.writerSheet().build();

            //数据写入
            Map<String, Object> excelDataMap = new HashMap<>();
            excelDataMap.put(MesExtConstWords.TITLE, excelName);
            excelWriter.fill(excelDataMap, writeSheet);

            excelWriter.finish();
            bos.flush();

            SysFile file = imppFileService.upload(excelFile, CommonEnumUtil.SOFT_TYPE.MES.getValue());

            log.info("MES援交报表 --- DOWNLOAD SUCCESS --- [{}]URL:[{}] --- THREAD:[{}]", excelName, file.getFilePath(), Thread.currentThread().getName());

            resp.setCharacterEncoding("UTF-8");
            resp.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(excelName, "UTF-8"));

            FileExtUtil.exportFile(resp, excelFile);

        } catch (IOException e) {
            e.printStackTrace();
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.IO_EXCEPTION_FILE.getCode())
                    .setErrorDetail("创建文件异常" + excelName + ".xlsx")
                    .build();
        } catch (ImppBusiException e) {
            e.printStackTrace();
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.IO_EXCEPTION_FILE.getCode())
                    .setErrorDetail(ExceptionUtils.getStackTrace(e))
                    .build();
        } catch (Exception e) {
            e.printStackTrace();
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.IO_EXCEPTION_FILE.getCode())
                    .setErrorDetail(ExceptionUtils.getStackTrace(e))
                    .build();
        } finally {
            if(fileTemplate != null && fileTemplate.exists()) {
                fileTemplate.delete();
            }
            if(excelFile != null && excelFile.exists()) {
                excelFile.delete();
            }
            if (fos != null){
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

        }

    }

    private void checkData4DownLoad(List<MesAssistOutAndEnter> dataList) {
        if (CollectionUtils.isEmpty(dataList))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("当前条件查询暂无数据,导出失败")
                    .build();
    }

    private List<SxAssistOutAndEnterModel> overrideDataList(SxAssistOutAndEnterReportModel data, List<MesAssistOutAndEnter> dataList) {
        List<SxAssistOutAndEnterModel> resultList = new ArrayList<>();

        Map<String, String> categoryMap = getCenterCategoryMap(data.getOrganizeCode());
        Map<String, List<MesAssistOutAndEnter>> dataMap = dataList.stream().filter(o -> null != o).collect(Collectors.groupingBy(MesAssistOutAndEnter::getOwnerDepartment));

        for(Map.Entry<String, List<MesAssistOutAndEnter>> entry : dataMap.entrySet()) {
            if (null == entry) continue;

            Double statistics = entry.getValue().stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getAmount()))).mapToDouble(MesAssistOutAndEnter::getAmount).sum();

            List<SxAssistOutAndEnterModel> keyList = new ArrayList<>();
            for (MesAssistOutAndEnter item : entry.getValue()) {
                if (null == item) continue;
                SxAssistOutAndEnterModel result = new SxAssistOutAndEnterModel();
                BeanUtils.copyProperties(item, result);
                result.setStatistics(statistics);
                result.setDate(result.getEndTime().substring(0, 10));
                if (!result.getInfluenceDate().equals(result.getDate()))
                    result.setDate(new StringJoiner(MesExtConstWords.E_LINE).add(result.getInfluenceDate()).add(result.getDate()).toString());
                result.setOwnerDepartmentName(data.getOwnerDepartmentMap().get(result.getOwnerDepartment()));
                if (!CollectionUtils.isEmpty(categoryMap) && categoryMap.containsKey(result.getWorkCenterCode()))
                    result.categoryCode(categoryMap.get(result.getWorkCenterCode()).split(MesExtConstWords.AND)[0])
                            .categoryName(categoryMap.get(result.getWorkCenterCode()).split(MesExtConstWords.AND)[1]);
                if (StringUtils.isEmpty(result.getCategoryCode())) result.categoryCode(MesExtConstWords.EMPTY);
                keyList.add(result);
            }

            resultList.addAll(keyList.stream().filter(o -> null != o).sorted(Comparator.comparing(SxAssistOutAndEnterModel::getCategoryCode)).collect(Collectors.toList()));
        }

        return resultList;
    }

    private Map<String, String> getCenterCategoryMap(String organizeCode) {
        List<MesWorkCenterExt> workCenterExtList = prodOrgExtService.queryWorkCenterExtList(organizeCode);
        Map<String, String> categoryMap = getCategoryMap(organizeCode);
        return CollectionUtils.isEmpty(workCenterExtList) ? null :
                workCenterExtList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCategoryCode())))
                        .collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, o -> getCategoryStr(o.getCategoryCode(), categoryMap)));
    }

    private String getCategoryStr(String categoryCode, Map<String, String> categoryMap) {
        return new StringJoiner(MesExtConstWords.AND).add(categoryCode).add(
                (!CollectionUtils.isEmpty(categoryMap) && categoryMap.containsKey(categoryCode)) ? categoryMap.get(categoryCode) : categoryCode
        ).toString();
    }

    private Map<String, String> getCategoryMap(String organizeCode) {
        List<MesPartCategoryPlanRate> partCategoryPlanRateList = partCategoryPlanRateService.getPartCategoryPlanRateAllList(organizeCode);
        return CollectionUtils.isEmpty(partCategoryPlanRateList) ? null :
                partCategoryPlanRateList.stream().filter(o -> (null != o && !StringUtils.isEmpty(o.getCategoryCode()) &&
                        !StringUtils.isEmpty(o.getCategoryName()))).collect(Collectors.toMap(MesPartCategoryPlanRate::getCategoryCode, MesPartCategoryPlanRate::getCategoryName));
    }

    private void setCellValue4ResultList(Sheet sheet, List<SxAssistOutAndEnterModel> resultList) {
        Integer rowNum = TEMPLATE_LAST_ROW;

        String categoryCode = resultList.get(0).getCategoryCode();
        String ownerDepartment = resultList.get(0).getOwnerDepartment();
        Integer cIndex = TEMPLATE_LAST_ROW;
        Integer oIndex = TEMPLATE_LAST_ROW;
        for (SxAssistOutAndEnterModel result : resultList) {
            if (null == result) continue;
            if (!ownerDepartment.equals(result.getOwnerDepartment()) || !categoryCode.equals(result.getCategoryCode())) {
                addMergedRegionUnsafe(sheet, cIndex, rowNum, 1);
                cIndex = rowNum;
                categoryCode = result.getCategoryCode();
            }
            if (!ownerDepartment.equals(result.getOwnerDepartment())) {
                addMergedRegionUnsafe(sheet, oIndex, rowNum, 7);
                oIndex = rowNum;
                ownerDepartment = result.getOwnerDepartment();
            }

            SxExcelExtUtil.setCellValue(sheet.getRow(rowNum), new Integer[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12},
                    new String[]{ getObjStr(result.getDate()), getObjStr(result.getCategoryName()), getObjStr(result.getWorkContent()),
                            getObjStr(result.getInfluenceNumber()), getObjStr(result.getIntervalTime()), getObjStr(result.getInfluenceTime()),
                            getObjStr(result.getAmount()),  getObjStr(result.getOwnerDepartmentName()), getObjStr(result.getStatistics()),
                            result.getLiabilityAttribution() == null ? "" :  MesExtEnumUtil.LIABILITY_ATTRIBUTION.valueOfDescription(result.getLiabilityAttribution()),
                            getObjStr(result.getTakeOnConfirm()), getObjStr(result.getPersonResponsibleConfirm()), getObjStr(result.getResponsibleMinisterConfirm())});

            rowNum ++;

            if (resultList.size() == (rowNum - TEMPLATE_LAST_ROW)) {
                addMergedRegionUnsafe(sheet, cIndex, rowNum, 1);
                addMergedRegionUnsafe(sheet, oIndex, rowNum, 7);
            }
        }
    }

    private void addMergedRegionUnsafe(Sheet sheet, Integer firstRow, Integer lastRow, int CellCol) {
        SxExcelExtUtil.addMergedRegionUnsafe(sheet, firstRow, lastRow - 1, CellCol, CellCol);
    }

    private String getObjStr(Object obj) {
        if (StringUtils.isEmpty(obj)) return MesExtConstWords.EMPTY;
        if (obj instanceof Double) return String.valueOf(((Double) obj).intValue());
        return obj.toString();
    }

    private String getExcelTitle(SxAssistOutAndEnterReportModel data, List<SxAssistOutAndEnterModel> resultList) {
        return getTitleDate(data) + "制造课援出" + getTitleOwnerDepartment(data, resultList) + "费用明细";
    }

    private String getTitleDate(SxAssistOutAndEnterReportModel data) {
        String[] start = data.getStartTime().split(MesExtConstWords.E_LINE);
        String[] end = data.getEndTime().split(MesExtConstWords.E_LINE);
        return data.getStartTime().equals(data.getEndTime())
                ? String.format("%s年%s月", start[0], start[1])
                : String.format("%s年%s月-%s年%s月", start[0], start[1], end[0], end[1]);
    }

    private String getTitleOwnerDepartment(SxAssistOutAndEnterReportModel data, List<SxAssistOutAndEnterModel> resultList) {
        List<String> ownerDepartmentList = (resultList.stream().filter(o -> null != o).map(
                SxAssistOutAndEnterModel::getOwnerDepartment).collect(Collectors.toList())).stream().filter(o -> !StringUtils.isEmpty(o)).distinct().collect(Collectors.toList());
        if (ownerDepartmentList.size() == 1) return data.getOwnerDepartmentMap().get(ownerDepartmentList.get(0));
        StringJoiner sj = new StringJoiner(MesExtConstWords.SINGLE_SLASH);
        for (String ownerDepartment : ownerDepartmentList) {
            if (StringUtils.isEmpty(ownerDepartment)) continue;
            sj.add(data.getOwnerDepartmentMap().get(ownerDepartment));
        }
        return "（" + sj.toString() + "）";
    }

    @Override
    public Integer doAssistOutAndEnterAutoConfirm(SxAssistOutAndEnterModel model) {
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnter(model, false);
        List<MesAssistOutAndEnter> dataList = assistOutAndEnterRepository.findByHqlWhere(packBean);
        if (CollectionUtils.isEmpty(dataList)) return MesExtConstWords.ZERO;
        try {
            if (!Objects.equals(model.getLevel(), MesExtEnumUtil.ASSIST_OUT_AND_ENTER_CONFIRM_LEVEL.RESPONSIBLE_MINISTERGE.getValue())){
                MesBusiConfig busiConfigDb = busiConfigRepository.getByProperty(new String[]{"organizeCode", "cfgCode", "cfgValueSeq", "isDeleted", "isValid"},
                        new Object[]{model.getOrganizeCode(), MesExtConstWords.TAKE_ON_CONFIRM_DEFAULT_LIABILITY_ATTRIBUTION,"10", CommonEnumUtil.TRUE_OR_FALSE.FALSE.getValue(), CommonEnumUtil.TRUE_OR_FALSE.TRUE.getValue()});
                if (busiConfigDb==null) model.setLiabilityAttribution(MesExtEnumUtil.LIABILITY_ATTRIBUTION.INTRA.getValue());
                else if(MesExtEnumUtil.LIABILITY_ATTRIBUTION.valueOfDescription(Integer.parseInt(busiConfigDb.getCfgValue())) == null)
                    log.info("MES工厂执行援交信息自动确认JOB --- EXEC ERROR --- 业务配置代码[TAKE_ON_CONFIRM_DEFAULT_LIABILITY_ATTRIBUTION][{}]责任归属维护有误,应为[10/20]其中一项", model.getLiabilityAttribution());
                else model.setLiabilityAttribution(Integer.parseInt(busiConfigDb.getCfgValue()));
            }
        }catch (Exception e){
            log.info("MES工厂执行援交信息自动确认JOB --- EXEC ERROR --- 业务配置代码[TAKE_ON_CONFIRM_DEFAULT_LIABILITY_ATTRIBUTION][{}]责任归属维护有误,应为[10/20]其中一项", model.getLiabilityAttribution());
            return MesExtConstWords.ZERO;
        }

        //避免对象为空
        doJobConfirmAssistOutAndEnterList(dataList,model.getLevel(),model.getLiabilityAttribution() == null ? 0 : model.getLiabilityAttribution());
        return dataList.size();
    }

    @Override
    public List<MesAssistOutAndEnter> queryAssistOutListByMonthAndContainProdTechnology(String influenceDateStart, String influenceDateEnd, String organizeCode) {
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnter(new SxAssistOutAndEnterModel(organizeCode, influenceDateStart, influenceDateEnd), false);
        DdlPreparedPack.getNumNOEqualPack(MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue(), MesExtConstWords.ASSIST_OUT_AND_ENTER_DETAIL, packBean);
        //责任部门为 生产技术 责任部门枚举在业务配置中进行维护 配置代码：OWNER_DEPARTMENT_CFG
        DdlPreparedPack.getStringEqualPack("20", MesExtConstWords.OWNER_DEPARTMENT, packBean);
        return assistOutAndEnterRepository.findByHqlWhere(packBean);
    }

    @Override
    public List<MesAssistOutAndEnter> queryAssistOutListByMonthWorkCenterCode(String influenceDateStart, String influenceDateEnd, String workCenterCode,String organizeCode) {
        DdlPackBean packBean = MesExtHqlPack.getAssistOutAndEnterEam(new SxAssistOutAndEnterModel(organizeCode,workCenterCode, influenceDateStart, influenceDateEnd), false);
        DdlPreparedPack.getNumNOEqualPack(MesExtEnumUtil.BU_ASSIST_OUT_AND_ENTER_DETAIL.ASSIST_ENTER.getValue(), MesExtConstWords.ASSIST_OUT_AND_ENTER_DETAIL, packBean);
        //责任部门为 生产技术 责任部门枚举在业务配置中进行维护 配置代码：OWNER_DEPARTMENT_CFG
        DdlPreparedPack.getStringEqualPack("20", MesExtConstWords.OWNER_DEPARTMENT, packBean);
        return assistOutAndEnterRepository.findByHqlWhere(packBean);
    }

    @Override
    public void doReportResponsibleMinisterConfirm(SxAssistOutAndEnterReportModel data) {
        Map<String, String> ownerDepartmentMap = busiConfigService.getConfigMap(data.getOrganizeCode(), MesExtConstWords.OWNER_DEPARTMENT_CFG);
        //根据开始时间-结束时间查找未进行责任部长确认 但 已担当确认&责任人确认的明细数据
        SxAssistOutAndEnterModel queryParams = new SxAssistOutAndEnterModel(data.getOrganizeCode(),
                data.getStartTime()+MesExtConstWords.DATE_DD_01,
                TimeTool.timeCalc(TimeTool.stringParseToDate(data.getEndTime(), MesExtConstWords.DATE_FORMAT_YM), Calendar.MONTH, 1, MesExtConstWords.DATE_FORMAT_YM) + MesExtConstWords.DATE_DD_01,
                true,true,false).ownerDepartmentArr(data.getOwnerDepartmentArr());
        List<MesAssistOutAndEnter> dataList = assistOutAndEnterRepository.findByHqlWhere(MesExtHqlPack.getAssistOutAndEnter(queryParams,false));

        String ownerDepartmentName = "";
        for (String ownerDepartment : data.getOwnerDepartmentArr().split(",")) {
            ownerDepartmentName += ownerDepartmentMap.getOrDefault(ownerDepartment, ownerDepartment);
        }
        if (CollectionUtils.isEmpty(dataList))
            throw ImppExceptionBuilder.newInstance()
                .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                .setErrorDetail("[%s]责任部门[%s]当前账号[%s]无需要部长确认的数据",
                        data.getStartTime()+"-"+data.getEndTime(),ownerDepartmentName,AuthUtil.getSessionUser().getUserName())
                .build();
        log.info("部长确认过滤前list:[{}],userLoginName:[{}]",JSONObject.toJSONString(dataList),data.getUserLoginName());

        //剔除责任部长不包含当前用户的明细
        dataList = filterDataList(dataList,data.getUserLoginName());
        log.info("部长确认过滤后list:[{}],userLoginName:[{}]",JSONObject.toJSONString(dataList),data.getUserLoginName());

        if (CollectionUtils.isEmpty(dataList))
            throw ImppExceptionBuilder.newInstance()
                    .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                    .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                    .setErrorDetail("[%s]责任部门[%s]当前账号[%s]无需要部长确认的数据",
                            data.getStartTime()+"-"+data.getEndTime(),ownerDepartmentName,AuthUtil.getSessionUser().getUserName())
                    .build();

        //更新责任部长确认信息
        doUpdateResponsibleMinisterConfirmInfo(dataList);
    }

    void doUpdateResponsibleMinisterConfirmInfo(List<MesAssistOutAndEnter> dataList){
        String userName = AuthUtil.getSessionUser().getUserName();
        for (MesAssistOutAndEnter outAndEnter : dataList) {
            outAndEnter.setSystemSyncStatus(MesExtEnumUtil.IF_SYNC_STATUS.NO_SYNC.getValue());
            ConvertBean.serviceModelUpdate(outAndEnter,userName);
            outAndEnter.setResponsibleMinisterConfirm(userName);
            outAndEnter.setResponsibleMinisterConfirmTime(outAndEnter.getModifyDatetime());
            assistOutAndEnterRepository.update(outAndEnter);
        }
    }

    private List<MesAssistOutAndEnter> filterDataList(List<MesAssistOutAndEnter> dataList,String userLoginName) {
        dataList = CollectionUtils.isEmpty(dataList) ? null : dataList.stream().filter(o -> (null != o &&
                Arrays.asList(o.getResponsibleMinister().split(",")).contains(userLoginName))).collect(Collectors.toList());
        return dataList;
    }

    public PushDataNotifyModel getAssistOutAndEnterDingPushInfo(MesAssistOutAndEnter assistOutAndEnter, Integer flag,Map<String, String> ownerDepartmentMap) {
        PushDataNotifyModel data = new PushDataNotifyModel();

        SxAssistOutAndEnterPushDingInfoModel pushDingInfoModel = new SxAssistOutAndEnterPushDingInfoModel();
        BeanUtils.copyProperties(assistOutAndEnter,pushDingInfoModel);
        //无级别 说明是新增 新增推送信息给担当
        flag = flag == null ? 0 : flag;
        switch (flag) {
            case 10:
                pushDingInfoModel.setUserNames(assistOutAndEnter.getPersonResponsible());
                break;
            case 20:
                pushDingInfoModel.setUserNames(assistOutAndEnter.getResponsibleMinister());
                break;
            default:
                pushDingInfoModel.setUserNames(assistOutAndEnter.getTakeOn());
                break;
        }
        if (ownerDepartmentMap!=null && ownerDepartmentMap.containsKey(pushDingInfoModel.getOwnerDepartment())) pushDingInfoModel.setOwnerDepartment(ownerDepartmentMap.get(pushDingInfoModel.getOwnerDepartment()));
        data.setApiParam(JSONObject.toJSONString(pushDingInfoModel));
        data.setPushName(MesExtConstWords.ASSIST_OUT_AND_ENTER_CONFIRM_PUSH_NAME);
        return data;
    }
}
