package cn.estsh.i3plus.ext.mes.apiservice.serviceimpl.busi;

import cn.estsh.i3plus.ext.mes.api.busi.IProjectBadRateService;
import cn.estsh.i3plus.ext.mes.pojo.bean.*;
import cn.estsh.i3plus.ext.mes.pojo.model.BoardProdcueQtyModel;
import cn.estsh.i3plus.ext.mes.pojo.model.ProjectBadRateModel;
import cn.estsh.i3plus.ext.mes.pojo.repository.*;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtConstWords;
import cn.estsh.i3plus.ext.mes.pojo.util.MesExtEnumUtil;
import cn.estsh.i3plus.mes.apiservice.util.DateUtil;
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.enumutil.CommonEnumUtil;
import cn.estsh.i3plus.pojo.base.tool.DdlPreparedPack;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkCenter;
import cn.estsh.i3plus.pojo.mes.bean.MesWorkOrder;
import cn.estsh.impp.framework.boot.exception.ImppExceptionBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 文件描述
 *
 * @author xiangming.liao
 * @date 2021年06月16日 10:37
 */
@Service
@Slf4j
public class ProjectBadRateService implements IProjectBadRateService {

    @Autowired
    private MesWorkCenterExtRepository workCenterExtRepository;
    @Autowired
    private MesWorkOrderExtRepository workOrderExtRepository;
    @Autowired
    private MesShiftProdCenterRecordRepository shiftProdCenterRecordRepository;
    @Autowired
    private MesPartExtRepository partExtRDao;
    @Autowired
    private MesRepairTaskRepository repairTaskRDao;
    @Autowired
    private MesOutPutStatisticsRepository outPutStatisticsRDao;
    @Autowired
    private MesProduceSnExtRepository produceSnExtRDao;
    @Autowired
    private MesBusiConfigRepository busiConfigRepository;
    @Autowired
    private MesShiftProdCenterRecordRepository shiftProdCenterRecordDao;

    //看板生产计划达成率标志
    public static final String MAIN_BOARD_PRODUCT_PLAN_RATE = "MAIN_BOARD_PRODUCT_PLAN_RATE";

    @Override
    public List<ProjectBadRateModel> queryProjectBadRate(String organizeCode) throws ParseException {
        //返回集合
        List<ProjectBadRateModel> rateModels = null;
        //获取所有本体线信息
        List<MesWorkCenterExt> allWorkCenterExt = getAllWorkCenterExt(organizeCode);

        if (!CollectionUtils.isEmpty(allWorkCenterExt)) {
            rateModels = new ArrayList<>();
            //遍历本体线  组装返回集合数据
            for (MesWorkCenterExt centerExt : allWorkCenterExt) {
                ProjectBadRateModel projectBadRateModel = new ProjectBadRateModel();
                //产线代码
                String workCenterCode = centerExt.getWorkCenterCode();
                projectBadRateModel.setWorkCenterCode(workCenterCode);
                //产线名称
                projectBadRateModel.setWorkCenterName(centerExt.getWorkCenterName());
                String shiftCode = centerExt.getShiftCode();
                //工单作业时间
                String workTime = centerExt.getWorkTime();
                if (StringUtils.isEmpty(workTime)) {
                    workTime = TimeTool.getToday();
                }

                //标准工时
                //标准作业时间 ：各产品当日实绩数量*产品标准工时然后进行汇总。
                double standardWorkTime = 0.0;

                //查询下线数据
                List<MesOutPutStatistics> outPutStatisticsList = getOutPutStatistics(workCenterCode, workTime, null, null, organizeCode);
                List<MesOutPutStatistics> outPutStatisticsListByShiftCode = CollectionUtils.isEmpty(outPutStatisticsList) ? new ArrayList<>(1) : outPutStatisticsList.stream().filter(mesOutPutStatistics -> mesOutPutStatistics != null && !StringUtils.isEmpty(mesOutPutStatistics.getShiftCode()) && mesOutPutStatistics.getShiftCode().equals(shiftCode)).collect(Collectors.toList());
                Map<String, List<MesOutPutStatistics>> snMapGroupByPartNo = outPutStatisticsListByShiftCode.stream().collect(Collectors.groupingBy(MesOutPutStatistics::getPartNo));
//                List<MesProduceSnExt> snExtList = getMesProduceSnExtsByShiftCode(workCenterCode, workTime, organizeCode,shiftCode);
//
//                Map<String, List<MesProduceSnExt>> snMapGroupByPartNo = snExtList.stream().collect(Collectors.groupingBy(MesProduceSnExt::getPartNo));

                for (Map.Entry<String, List<MesOutPutStatistics>> snListEntry : snMapGroupByPartNo.entrySet()) {
                    //物料编码
                    String partNo = snListEntry.getKey();
                    //物料信息
                    MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
                    //物料标准工数
                    Double standardWork = mesPartExt.getStandardWork();
                    if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
                        standardWork = 1.0;
                    }

                    //物料的完成数量（各产品当日实绩数量）
                    Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                    //产品标准工时
                    double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);

                    //各产品当日产品标准工时进行累加。
                    standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
                }

//                for (Map.Entry<String, List<MesProduceSnExt>> snListEntry : snMapGroupByPartNo.entrySet()) {
//                    //物料编码
//                    String partNo = snListEntry.getKey();
//                    //物料信息
//                    MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
//                    //物料标准工数
//                    Double standardWork = mesPartExt.getStandardWork();
//                    if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
//                        standardWork = 1.0;
//                    }
//
//                    //物料的完成数量（各产品当日实绩数量）
//                    Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesProduceSnExt::getQty).reduce(0.00, Double::sum);
//
//                    //产品标准工时
//                    double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);
//
//                    //各产品当日产品标准工时进行累加。
//                    standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
//                }

                //当日实际生产
                Double sumCompleteQty = outPutStatisticsList.stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                //当前产线停开机记录
                List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecord(workCenterCode, shiftCode, workTime, organizeCode);

                //过滤停开机作业记录中 常规生产的数据（正常上班）
                List<MesShiftProdCenterRecord> conventionList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()))).collect(Collectors.toList());
                //当前常规作业时长（正常上班）
                Double conventionWorkTime = getServiceWorkTime(conventionList);

                //过滤停开机作业记录中 非常规生产的数据（加班上班）
                List<MesShiftProdCenterRecord> unConventionList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()))).collect(Collectors.toList());
                //当前非常规作业时长（加班上班）
                Double unConventionWorkTime = getServiceWorkTime(unConventionList);

                //过滤停开机作业记录中 非常规停机的数据（异常停机）
                List<MesShiftProdCenterRecord> unnormalStopCenterList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                //当前非常规停机时长（非作业时长）
                Double unormalStopCenterTime = getServiceWorkTime(unnormalStopCenterList);

                //过滤停开机作业记录中 常规停机的数据（常规停机）
                List<MesShiftProdCenterRecord> stopCenterList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                //当前常规停机的数据（非作业时长）
                Double stopCenterTime = getServiceWorkTime(stopCenterList);


                //总作业时间：(当前常规作业时长+当前非常规作业时长)-当前非常规停机时长
                Double totalWorkTime = MathOperation.sub(MathOperation.add(conventionWorkTime, unConventionWorkTime), MathOperation.add(unormalStopCenterTime, stopCenterTime));


                //作业能率 = 标准作业时间/（勤务时间-非作业时间) * 100%,保留一位小数
                //作业能率 =标准作业时间/总作业时间*100%，保留一位小数
                BigDecimal workRateBigDecimal = BigDecimal.valueOf(totalWorkTime);
                BigDecimal workRate = workRateBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(workRateBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                projectBadRateModel.setWorkRate(workRate.doubleValue());

                //总勤务时间
                Double serviceWorkTime = MathOperation.add(conventionWorkTime, unConventionWorkTime);
                //综合能率：标准作业时间/勤务时间*100%，保留1位小数。
                BigDecimal serviceWorkTimeBigDecimal = BigDecimal.valueOf(serviceWorkTime);
                BigDecimal totalRate = serviceWorkTimeBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(serviceWorkTimeBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                projectBadRateModel.setTotalRate(totalRate.doubleValue());

                //过滤当日下线中的所有工单
                List<String> outPutWoNoList = outPutStatisticsList.stream().map(MesOutPutStatistics::getWorkOrderNo).collect(Collectors.toList());
                List<MesRepairTask> repairTasks = getMesRepairTasksByTodayAndWoNo(outPutWoNoList, organizeCode);
                Double repairQty = repairTasks.stream().map(MesRepairTask::getRepairQty).reduce(0.00, Double::sum);
                //不良率 = 当日不良数量汇总/当日实绩汇总*100%，保留1位小数。
                if (BigDecimal.valueOf(sumCompleteQty).compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal defectiveRate = BigDecimal.valueOf(repairQty).compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(repairQty).divide(BigDecimal.valueOf(sumCompleteQty), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                    projectBadRateModel.setDefectiveRate(defectiveRate.doubleValue());
                } else {
                    projectBadRateModel.setDefectiveRate(0.0);
                }

                //当日实际生产
                projectBadRateModel.setProduceQty(sumCompleteQty.intValue());

                //当前日期
                String today = TimeTool.getToday();

                //通过产线查询当天计划数量
                //查询当天所有的有效工单
                List<MesWorkOrderExt> orderExtList = getWorkOrderExts(workCenterCode, today, organizeCode);

                //计划数量
                Double sumQty = orderExtList.stream().map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);
                projectBadRateModel.setPlanQty(sumQty.intValue());

                rateModels.add(projectBadRateModel);
            }

        }

        return rateModels;
    }

    @Override
    public List<ProjectBadRateModel> queryEpProjectBadRate(String organizeCode) throws ParseException {

        //返回集合
        List<ProjectBadRateModel> rateModels = new ArrayList<>();

        List<MesBusiConfig> busiConfigWorkCenterList = getBusiConfigWorkCenterList(organizeCode);

        //无配置
        if (CollectionUtils.isEmpty(busiConfigWorkCenterList)){
            return rateModels;
        }

        List<MesWorkCenterExt> workCenterExtList = getWorkCenterExtByCode(organizeCode, busiConfigWorkCenterList.stream().map(MesBusiConfig::getCfgValue).collect(Collectors.toList()));
        List<String> workCenterCodes = workCenterExtList.stream().map(MesWorkCenter::getWorkCenterCode).collect(Collectors.toList());
        Map<String, MesWorkCenterExt> workCenterMap = workCenterExtList.stream().collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, Function.identity(), (oldData, newData) -> newData));

        //根据当前系统时间是存在停开机记录当中的数据
        List<MesShiftProdCenterRecord> shiftProdCenterRecordByNowList = getShiftProdCenterRecordByNow(workCenterCodes, organizeCode);
        //获取当前产线启动状态
        Map<String, MesShiftProdCenterRecord> stringMesShiftProdCenterRecordMap = getShiftProdCenterRecordOnlyOneMap(shiftProdCenterRecordByNowList);
        //根据产线分组获取停开机记录
        Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordByCenterMap = getShiftProdCenterRecordByCenterMap(shiftProdCenterRecordByNowList);

        //根据作业时间时间获取产量统计数据

        //获取所有本体线信息
        for (MesBusiConfig busiConfig : busiConfigWorkCenterList) {
            if (!CollectionUtils.isEmpty(workCenterExtList)) {
                //遍历本体线  组装返回集合数据
                MesWorkCenterExt workCenterExtDb = CollectionUtils.isEmpty(workCenterMap) ? null : workCenterMap.get(busiConfig.getCfgValue());
                if(workCenterExtDb != null){
                    //工单作业时间
                    String workTime = workCenterExtDb.getWorkTime();
                    if (StringUtils.isEmpty(workTime)) {
                        workTime = TimeTool.getToday();
                    }

                    //通过产线查询当天计划数量
                    //查询当天所有的有效工单
                    List<MesWorkOrderExt> workOrderExtList = getWorkOrderExtsContainReusePlanDatetime(workCenterExtDb.getWorkCenterCode(), workTime, organizeCode);

                    //查询当天所有的有效工单
                    Map<String, MesWorkOrderExt> workOrderMap = getWorkOrderMap(workOrderExtList);

                    //通过产线查询当天计生产实绩
                    List<MesOutPutStatistics> outPutStatisticsList = getMesOutPutStatistics(organizeCode, workCenterExtDb, workTime);

                    //当前生产或待生产的启动工单
                    MesWorkOrder mesWorkOrder = CollectionUtils.isEmpty(workOrderMap) || !workOrderMap.containsKey(workCenterExtDb.getWorkCenterCode()) ? null : workOrderMap.get(workCenterExtDb.getWorkCenterCode());

                    //获取当前产线停开机记录
                    MesShiftProdCenterRecord shiftProdCenterRecord = CollectionUtils.isEmpty(stringMesShiftProdCenterRecordMap) ? null : stringMesShiftProdCenterRecordMap.get(workCenterExtDb.getWorkCenterCode());

                    // 无启动工单
                    if((mesWorkOrder == null && CollectionUtils.isEmpty(outPutStatisticsList)) || (shiftProdCenterRecord == null)) {
                        continue;
                    }

                    ProjectBadRateModel projectBadRateModel = new ProjectBadRateModel();
                    //产线代码
                    String workCenterCode = workCenterExtDb.getWorkCenterCode();
                    projectBadRateModel.setWorkCenterCode(workCenterCode);
                    //产线名称
                    projectBadRateModel.setWorkCenterName(workCenterExtDb.getWorkCenterName());
                    //产线描述
                    projectBadRateModel.setWorkCenterDesc(workCenterExtDb.getWorkCenterDesc());
                    String shiftCode = workCenterExtDb.getShiftCode();

                    //标准工时
                    //标准作业时间 ：各产品当日实绩数量*产品标准工时然后进行汇总。
                    double standardWorkTime = 0.0;

                    //查询下线数据
                    //List<MesOutPutStatistics> outPutStatisticsList = getOutPutStatistics(workCenterCode, workTime, null, null, organizeCode);
                    //List<MesOutPutStatistics> outPutStatisticsListByShiftCode = getOutPutStatisticsByShiftCode(outPutStatisticsList, shiftCode);
                    //List<MesOutPutStatistics> outPutStatisticsListByShiftCode = getOutPutStatistics(workCenterCode, workTime, shiftCode, null, organizeCode);
                    Map<String, List<MesOutPutStatistics>> snMapGroupByPartNo = getSnMapGroupByPartNo(outPutStatisticsList, shiftCode);

                    for (Map.Entry<String, List<MesOutPutStatistics>> snListEntry : snMapGroupByPartNo.entrySet()) {
                        //物料编码
                        String partNo = snListEntry.getKey();
                        //物料信息
                        MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
                        //物料标准工数
                        Double standardWork = mesPartExt.getStandardWork();
                        if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
                            standardWork = 1.0;
                        }

                        //物料的完成数量（各产品当日实绩数量）
                        Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                        //产品标准工时
                        double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);

                        //各产品当日产品标准工时进行累加。
                        standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
                    }

                    //当日实际生产
                    Double sumCompleteQty = outPutStatisticsList.stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                    //根据班次分组获取
                    //Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordByShiftCodeMap = getMesShiftProdCenterRecordByShiftCodeMap(shiftProdCenterRecordByCenterMap, workCenterCode);

                    //当前产线停开机记录
                    List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecord(workCenterCode, shiftCode, workTime, organizeCode);
                    //List<MesShiftProdCenterRecord> shiftProdCenterRecordList = shiftProdCenterRecordByShiftCodeMap.get(shiftCode);
                    //过滤停开机作业记录中 常规生产的数据（正常上班）
                    List<MesShiftProdCenterRecord> conventionList = shiftProdCenterRecordList.stream().filter(
                            o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()))).collect(Collectors.toList());
                    //当前常规作业时长（正常上班）
                    Double conventionWorkTime = getServiceWorkTime(conventionList);

                    //过滤停开机作业记录中 非常规生产的数据（加班上班）
                    List<MesShiftProdCenterRecord> unConventionList = shiftProdCenterRecordList.stream().filter(
                            o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()))).collect(Collectors.toList());
                    //当前非常规作业时长（加班上班）
                    Double unConventionWorkTime = getServiceWorkTime(unConventionList);

                    //过滤停开机作业记录中 非常规停机的数据（异常停机）
                    List<MesShiftProdCenterRecord> unnormalStopCenterList = shiftProdCenterRecordList.stream().filter(
                            o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                    //当前非常规停机时长（非作业时长）
                    Double unormalStopCenterTime = getServiceWorkTime(unnormalStopCenterList);

                    //过滤停开机作业记录中 常规停机的数据（常规停机）
                    List<MesShiftProdCenterRecord> stopCenterList = shiftProdCenterRecordList.stream().filter(
                            o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                    //当前常规停机的数据（非作业时长）
                    Double stopCenterTime = getServiceWorkTime(stopCenterList);

                    //总作业时间：(当前常规作业时长+当前非常规作业时长)-当前非常规停机时长
                    Double totalWorkTime = MathOperation.sub(MathOperation.add(conventionWorkTime, unConventionWorkTime), MathOperation.add(unormalStopCenterTime, stopCenterTime));

                    //作业能率 = 标准作业时间/（勤务时间-非作业时间) * 100%,保留一位小数
                    //作业能率 = 标准作业时间/总作业时间*100%，保留一位小数
                    BigDecimal workRateBigDecimal = BigDecimal.valueOf(totalWorkTime);
                    BigDecimal workRate = workRateBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(workRateBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                    projectBadRateModel.setWorkRate(workRate.doubleValue());

                    //总勤务时间
                    Double serviceWorkTime = MathOperation.add(conventionWorkTime, unConventionWorkTime);
                    //综合能率：标准作业时间/勤务时间*100%，保留1位小数。
                    BigDecimal serviceWorkTimeBigDecimal = BigDecimal.valueOf(serviceWorkTime);
                    BigDecimal totalRate = serviceWorkTimeBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(serviceWorkTimeBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                    projectBadRateModel.setTotalRate(totalRate.doubleValue());

                    //过滤当日下线中的所有工单
                    List<String> outPutWoNoList = outPutStatisticsList.stream().map(MesOutPutStatistics::getWorkOrderNo).collect(Collectors.toList());
                    List<MesRepairTask> repairTasks = getMesRepairTasksByTodayAndWoNo(outPutWoNoList, organizeCode);
                    Double repairQty = repairTasks.stream().map(MesRepairTask::getRepairQty).reduce(0.00, Double::sum);
                    //不良率 = 当日不良数量汇总/当日实绩汇总*100%，保留1位小数。
                    if (BigDecimal.valueOf(sumCompleteQty).compareTo(BigDecimal.ZERO) > 0) {
                        BigDecimal defectiveRate = BigDecimal.valueOf(repairQty).compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(repairQty).divide(BigDecimal.valueOf(sumCompleteQty), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                        projectBadRateModel.setDefectiveRate(defectiveRate.doubleValue());
                    } else {
                        projectBadRateModel.setDefectiveRate(0.0);
                    }

                    //当日实际生产
                    projectBadRateModel.setProduceQty(sumCompleteQty.intValue());

                    //当前日期
                    //String today = TimeTool.getToday();

                    //通过产线查询当天计划数量
                    //查询当天所有的有效工单
                    //List<MesWorkOrderExt> orderExtList = getWorkOrderExts(workCenterCode, today, organizeCode);

                    //计划数量
                    //Double sumQty = workOrderExtList.stream().map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);

                    //计划数量
                    Double sumQty = workOrderExtList.stream().filter(mesWorkOrderExt -> StringUtils.isEmpty(mesWorkOrderExt.getReusePlanDatetime())).map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);
                    //复用计划数量
                    Double reuseSumQty = workOrderExtList.stream().filter(mesWorkOrderExt -> !StringUtils.isEmpty(mesWorkOrderExt.getReusePlanDatetime())).map(MesWorkOrderExt::getReusePlanCompleteQty).reduce(0.00, Double::sum);
                    projectBadRateModel.setPlanQty(sumQty.intValue() + reuseSumQty.intValue());
                    //projectBadRateModel.setPlanQty(sumQty.intValue());

                    if(sumCompleteQty != 0 || sumQty != 0){
                        rateModels.add(projectBadRateModel);
                    }
                }
            }
        }

        return rateModels;
    }

    private Map<String, List<MesShiftProdCenterRecord>> getMesShiftProdCenterRecordByShiftCodeMap(Map<String, List<MesShiftProdCenterRecord>> shiftProdCenterRecordByCenterMap, String workCenterCode) {
        List<MesShiftProdCenterRecord> shiftProdCenterRecordByWorkCenterCodeList = shiftProdCenterRecordByCenterMap.get(workCenterCode);
        return shiftProdCenterRecordByWorkCenterCodeList.stream().collect(Collectors.groupingBy(MesShiftProdCenterRecord::getShiftCode));
    }

    private Map<String, List<MesOutPutStatistics>> getSnMapGroupByPartNo(List<MesOutPutStatistics> outPutStatisticsList, String shiftCode){
        List<MesOutPutStatistics> outPutStatisticsListByShiftCode = CollectionUtils.isEmpty(outPutStatisticsList) ? null : outPutStatisticsList.stream().filter(outPutStatistics -> !StringUtils.isEmpty(outPutStatistics.getShiftCode()) && outPutStatistics.getShiftCode().equals(shiftCode)).collect(Collectors.toList());
        return CollectionUtils.isEmpty(outPutStatisticsListByShiftCode) ? new HashMap<>(1) : outPutStatisticsListByShiftCode.stream().collect(Collectors.groupingBy(MesOutPutStatistics::getPartNo));
    }

    private Map<String, MesShiftProdCenterRecord> getShiftProdCenterRecordOnlyOneMap(List<MesShiftProdCenterRecord> shiftProdCenterRecordByNowList) {
        return  shiftProdCenterRecordByNowList.stream().collect(
                Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing((wo1, wo2) -> wo1.getModifyDatetime().compareTo(wo2.getModifyDatetime()) > 0 ? wo1 : wo2), Optional::get)));
    }

    private Map<String, List<MesShiftProdCenterRecord>> getShiftProdCenterRecordByCenterMap(List<MesShiftProdCenterRecord> shiftProdCenterRecordByNowList) {
        return shiftProdCenterRecordByNowList.stream().collect(
                Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode));
    }

    private Map<String, MesWorkOrderExt> getWorkOrderMap(List<MesWorkOrderExt> workOrderExtList) {
        return CollectionUtils.isEmpty(workOrderExtList) ? null : workOrderExtList.stream().collect(
                Collectors.groupingBy(MesWorkOrderExt::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing(( wo1,wo2) -> wo1.getSeq().compareTo(wo2.getSeq()) < 0? wo1:wo2), Optional::get)));
    }

    private MesBusiConfig getWorkPlanTargetRate(String organizeCode) {
        DdlPackBean packBean =  DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(MAIN_BOARD_PRODUCT_PLAN_RATE, MesExtConstWords.CFG_CODE, packBean);
        return busiConfigRepository.getByProperty(packBean);
    }


    @Override
    public List<ProjectBadRateModel> queryProjectBadRateByMonth(String workCenterCode, String organizeCode) throws ParseException {
        //返回集合
        List<ProjectBadRateModel> rateModels = null;
        //当前日期时间
        String currentTime = DateUtil.formatDate();
        String entTime = currentTime.substring(0, 10);
        String startTime = currentTime.substring(0, 7) + MesExtConstWords.DATE_DD_01;

        //这个月1号到当前时间的数据
        List<String> dayBetween = getDayBetween(startTime, entTime);

        rateModels = new ArrayList<>();

        //遍历查询截止到当前所有的
        for (String workTime : dayBetween) {
            ProjectBadRateModel projectBadRateModel = new ProjectBadRateModel();
            DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
            DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, packBean);
            MesWorkCenterExt centerExt = workCenterExtRepository.getByProperty(packBean);
            projectBadRateModel.setWorkTime(workTime.substring(5, 10));
            //产线代码
            projectBadRateModel.setWorkCenterCode(workCenterCode);
            //产线名称
            projectBadRateModel.setWorkCenterName(centerExt.getWorkCenterName());
            String shiftCode = centerExt.getShiftCode();
            //标准工时
            //标准作业时间 ：各产品当日实绩数量*产品标准工时然后进行汇总。
            double standardWorkTime = 0.0;

            //查询下线条码
            List<MesProduceSnExt> snExtList = getMesProduceSnExts(workCenterCode, workTime, organizeCode);

            Map<String, List<MesProduceSnExt>> snMapGroupByPartNo = snExtList.stream().collect(Collectors.groupingBy(MesProduceSnExt::getPartNo));

            for (Map.Entry<String, List<MesProduceSnExt>> snListEntry : snMapGroupByPartNo.entrySet()) {
                //物料编码
                String partNo = snListEntry.getKey();
                //物料信息
                MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
                //物料标准工数
                Double standardWork = mesPartExt.getStandardWork();
                if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
                    standardWork = 1.0;
                }

                //物料的完成数量（各产品当日实绩数量）
                Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesProduceSnExt::getQty).reduce(0.00, Double::sum);

                //产品标准工时
                double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);

                //各产品当日产品标准工时进行累加。
                standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
            }

            //当日实际生产
            Double sumCompleteQty = snExtList.stream().map(MesProduceSnExt::getQty).reduce(0.00, Double::sum);

            //当前产线停开机记录
            List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecord(workCenterCode, shiftCode, workTime, organizeCode);

            //过滤停开机作业记录中 常规生产的数据（正常上班）
            List<MesShiftProdCenterRecord> conventionList = shiftProdCenterRecordList.stream().filter(
                    o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()))).collect(Collectors.toList());
            //当前常规作业时长（正常上班）
            Double conventionWorkTime = getServiceWorkTime(conventionList);

            //过滤停开机作业记录中 非常规生产的数据（加班上班）
            List<MesShiftProdCenterRecord> unConventionList = shiftProdCenterRecordList.stream().filter(
                    o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()))).collect(Collectors.toList());
            //当前非常规作业时长（加班上班）
            Double unConventionWorkTime = getServiceWorkTime(unConventionList);

            //过滤停开机作业记录中 非常规停机的数据（异常停机）
            List<MesShiftProdCenterRecord> unnormalStopCenterList = shiftProdCenterRecordList.stream().filter(
                    o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
            //当前非常规停机时长（非作业时长）
            Double unormalStopCenterTime = getServiceWorkTime(unnormalStopCenterList);

            //过滤停开机作业记录中 常规停机的数据（常规停机）
            List<MesShiftProdCenterRecord> stopCenterList = shiftProdCenterRecordList.stream().filter(
                    o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
            //当前常规停机的数据（非作业时长）
            Double stopCenterTime = getServiceWorkTime(stopCenterList);

            //总作业时间：(当前常规作业时长+当前非常规作业时长)-当前非常规停机时长
            Double totalWorkTime = MathOperation.sub(MathOperation.add(conventionWorkTime, unConventionWorkTime), MathOperation.add(unormalStopCenterTime, stopCenterTime));

            //作业能率 = 标准作业时间/（勤务时间-非作业时间) * 100%,保留一位小数
            //作业能率 =标准作业时间/总作业时间*100%，保留一位小数
            BigDecimal workRateBigDecimal = BigDecimal.valueOf(totalWorkTime);
            BigDecimal workRate = workRateBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(workRateBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
            projectBadRateModel.setWorkRate(workRate.doubleValue());

            //总勤务时间
            Double serviceWorkTime = MathOperation.add(conventionWorkTime, unConventionWorkTime);
            //综合能率：标准作业时间/勤务时间*100%，保留1位小数。
            BigDecimal serviceWorkTimeBigDecimal = BigDecimal.valueOf(serviceWorkTime);
            BigDecimal totalRate = serviceWorkTimeBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(serviceWorkTimeBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
            projectBadRateModel.setTotalRate(totalRate.doubleValue());

            //过滤当日下线中的所有工单
            List<String> outPutWoNoList = snExtList.stream().map(MesProduceSnExt::getWorkOrderNo).collect(Collectors.toList());
            List<MesRepairTask> repairTasks = getMesRepairTasksByTodayAndWoNo(outPutWoNoList, organizeCode);
            Double repairQty = repairTasks.stream().map(MesRepairTask::getRepairQty).reduce(0.00, Double::sum);
            //不良率 = 当日不良数量汇总/当日实绩汇总*100%，保留1位小数。
            if (BigDecimal.valueOf(sumCompleteQty).compareTo(BigDecimal.ZERO) > 0) {
                BigDecimal defectiveRate = BigDecimal.valueOf(repairQty).compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(repairQty).divide(BigDecimal.valueOf(sumCompleteQty), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                projectBadRateModel.setDefectiveRate(defectiveRate.doubleValue());
            } else {
                projectBadRateModel.setDefectiveRate(0.0);
            }

            rateModels.add(projectBadRateModel);


        }

        return rateModels;
    }

    private Double getServiceWorkTime(List<MesShiftProdCenterRecord> modelList) throws ParseException {
        Iterator<MesShiftProdCenterRecord> iterator = modelList.iterator();

        Double workTimeByNow = 0.0;
        while (iterator.hasNext()) {
            MesShiftProdCenterRecord shiftProdCenterRecord = iterator.next();
            Date startTime = DateUtil.parse(shiftProdCenterRecord.getStartTime(), DateUtil.BASE_FORMAT);
            Date endTime = DateUtil.parse(shiftProdCenterRecord.getEndTime(), DateUtil.BASE_FORMAT);
            Date now = DateUtil.parse(TimeTool.getNowTime(true), DateUtil.BASE_FORMAT);

            //是否大于结束时间
            int isAfterEndTime = now.compareTo(DateUtil.parse(shiftProdCenterRecord.getEndTime(), DateUtil.BASE_FORMAT));

            //当前时间所在的作业区间
            if (TimeTool.isEffectiveDate(now, startTime, endTime)) {
                int secoundsBetweenTime = Math.abs(TimeTool.getSecoundsBetweenTime(2, shiftProdCenterRecord.getStartTime(), TimeTool.getNowTime(true)));
                double add = MathOperation.add(MathOperation.mul(secoundsBetweenTime, shiftProdCenterRecord.getWorkerQty()), workTimeByNow);
                workTimeByNow = add;
            } else {
                if (isAfterEndTime == 0 || isAfterEndTime == 1) {
                    int secoundsBetweenTime = Math.abs(TimeTool.getSecoundsBetweenTime(2, shiftProdCenterRecord.getStartTime(), shiftProdCenterRecord.getEndTime()));
                    double add = MathOperation.add(MathOperation.mul(secoundsBetweenTime, shiftProdCenterRecord.getWorkerQty()), workTimeByNow);
                    workTimeByNow = add;
                }
            }
        }

        return workTimeByNow;
    }

    private List<MesProduceSnExt> getMesProduceSnExtsByShiftCode(String workCenterCode, String workTime, String organizeCode, String shiftCode) {
        List<MesProduceSnExt> snExtList = new ArrayList<>();

        List<Integer> snStatusList = new ArrayList<>();
        snStatusList.add(MesExtEnumUtil.PRODUCE_SN_STATUS.ERR_OFFLINE.getValue());
        snStatusList.add(MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue());

        for (Integer snStatus : snStatusList) {
            DdlPackBean snPackBean = DdlPackBean.getDdlPackBean(organizeCode);
            DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, snPackBean);
            DdlPreparedPack.getStringEqualPack(workTime, MesExtConstWords.LOT_NO, snPackBean);
            DdlPreparedPack.getStringEqualPack(shiftCode, MesExtConstWords.SHIFT_CODE, snPackBean);

            DdlPreparedPack.getNumEqualPack(snStatus, "snStatus", snPackBean);
            snExtList.addAll(produceSnExtRDao.findByHqlWhere(snPackBean));
        }

        return snExtList;
    }

    private List<MesProduceSnExt> getMesProduceSnExts(String workCenterCode, String workTime, String organizeCode) {
        List<MesProduceSnExt> snExtList = new ArrayList<>();

        List<Integer> snStatusList = new ArrayList<>();
        snStatusList.add(MesExtEnumUtil.PRODUCE_SN_STATUS.ERR_OFFLINE.getValue());
        snStatusList.add(MesExtEnumUtil.PRODUCE_SN_STATUS.OFFLINE.getValue());

        for (Integer snStatus : snStatusList) {
            DdlPackBean snPackBean = DdlPackBean.getDdlPackBean(organizeCode);
            DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, snPackBean);
            DdlPreparedPack.getStringEqualPack(workTime, MesExtConstWords.LOT_NO, snPackBean);

            DdlPreparedPack.getNumEqualPack(snStatus, "snStatus", snPackBean);
            snExtList.addAll(produceSnExtRDao.findByHqlWhere(snPackBean));
        }

        return snExtList;
    }


    private MesPartExt getMesPartExt(String partNo, String organizeCode) {
        DdlPackBean partNoPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(partNo, MesExtConstWords.PART_NO, partNoPackBean);
        //物料信息
        MesPartExt mesPartExt = partExtRDao.getByProperty(partNoPackBean);
        return mesPartExt;
    }

    private List<MesRepairTask> getMesRepairTasksByTodayAndWoNo(List<String> outPutWoNoList, String organizeCode) {
        DdlPackBean repairTaskBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringRightLikerPack(TimeTool.getToday(), "repairDate", repairTaskBean);
        DdlPreparedPack.getInPackList(outPutWoNoList, MesExtConstWords.WORK_ORDER_NO, repairTaskBean);
        List<MesRepairTask> repairTasks = repairTaskRDao.findByHqlWhere(repairTaskBean);
        return repairTasks;
    }


    @Override
    public List<BoardProdcueQtyModel> queryBoardProduceQty(String organizeCode) {
        //查询所有本体线；
        List<MesWorkCenterExt> centerExtList = getAllWorkCenterExt(organizeCode);
        //当前日期
        String today = TimeTool.getToday();

        //返回結果集
        List<BoardProdcueQtyModel> requestList = new ArrayList<>();
        for (MesWorkCenterExt centerExt : centerExtList) {
            BoardProdcueQtyModel model = new BoardProdcueQtyModel();
            //产线代码 产线名称
            String workCenterCode = centerExt.getWorkCenterCode();
            model.setWorkCenterCode(workCenterCode);
            model.setWorkCenterName(centerExt.getWorkCenterName());
            String workTime = centerExt.getWorkTime();
            if (StringUtils.isEmpty(workTime)) {
                workTime = today;
            }

            //通过产线查询当天计生产实绩
            List<MesOutPutStatistics> outPutStatisticsList = getMesOutPutStatistics(organizeCode, centerExt, workTime);

            //生产实绩
            double produceQty = outPutStatisticsList.stream().mapToDouble(MesOutPutStatistics::getQty).sum();
            model.setProduceQty(produceQty);

            //通过产线查询当天计生产实绩
//            List<MesProduceSnExt> snExtList = getMesProduceSnExts(workCenterCode, workTime, organizeCode);
            //生产实绩
//            double produceQty = snExtList.stream().mapToDouble(MesProduceSnExt::getQty).sum();
//            model.setProduceQty(produceQty);

            //通过产线查询当天计划数量
            //查询当天所有的有效工单
            List<MesWorkOrderExt> orderExtList = getWorkOrderExts(workCenterCode, today, organizeCode);

            //计划数量
            Double sumQty = orderExtList.stream().map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);
            model.setPlanQty(sumQty);

            //产能占比=生产实绩/计划数量*100%，取一位小数;
            double produceRate = MathOperation.div(produceQty, sumQty, 3);

            model.setProduceRate(MathOperation.mul(produceRate, 100));

            requestList.add(model);
        }
        return requestList;
    }

    @Override
    public List<BoardProdcueQtyModel> queryEpBoardProduceQty(String organizeCode) {

        //返回結果集
        List<BoardProdcueQtyModel> requestList = new ArrayList<>();
        List<MesBusiConfig> busiConfigWorkCenterList = getBusiConfigWorkCenterList(organizeCode);
        //无配置
        if (CollectionUtils.isEmpty(busiConfigWorkCenterList)){
            return requestList;
        }

        List<String> workCenterCodeList = busiConfigWorkCenterList.stream().map(MesBusiConfig::getCfgValue).collect(Collectors.toList());

        List<MesWorkCenterExt> workCenterExtList = getWorkCenterExtByCode(organizeCode, workCenterCodeList);
        Map<String, MesWorkCenterExt> workCenterMap = workCenterExtList.stream().collect(Collectors.toMap(MesWorkCenterExt::getWorkCenterCode, Function.identity(), (oldData, newData) -> newData ));
        //当前日期
        String today = TimeTool.getToday();

        //当前系统时间去查询是存在停开机记录当中的数据
        List<MesShiftProdCenterRecord> shiftProdCenterRecordByNowList = getShiftProdCenterRecordByNow(workCenterCodeList, organizeCode);

        Map<String, MesShiftProdCenterRecord> shiftProdCenterRecordMap = CollectionUtils.isEmpty(shiftProdCenterRecordByNowList) ? null : shiftProdCenterRecordByNowList.stream().collect(
                Collectors.groupingBy(MesShiftProdCenterRecord::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing((wo1, wo2) -> wo1.getModifyDatetime().compareTo(wo2.getModifyDatetime()) > 0 ? wo1 : wo2), Optional::get)));

        for (MesBusiConfig busiConfig : busiConfigWorkCenterList) {
            MesWorkCenterExt workCenterExtDb = CollectionUtils.isEmpty(workCenterMap) ? null : workCenterMap.get(busiConfig.getCfgValue());
            if(workCenterExtDb != null){
                BoardProdcueQtyModel model = new BoardProdcueQtyModel();
                //产线代码 产线名称
                String workCenterCode = workCenterExtDb.getWorkCenterCode();
                model.setWorkCenterCode(workCenterCode);
                model.setWorkCenterName(workCenterExtDb.getWorkCenterName());
                model.setWorkCenterDesc(workCenterExtDb.getWorkCenterDesc());
                String workTime = workCenterExtDb.getWorkTime();
                if (StringUtils.isEmpty(workTime)) {
                    workTime = today;
                }

                //通过产线查询当天计划数量
                //查询当天所有的有效工单
                List<MesWorkOrderExt> workOrderExtList = getWorkOrderExtsContainReusePlanDatetime(workCenterCode, today, organizeCode);

                Map<String, MesWorkOrderExt> workOrderMap = CollectionUtils.isEmpty(workOrderExtList) ? null : workOrderExtList.stream().collect(
                        Collectors.groupingBy(MesWorkOrderExt::getWorkCenterCode, Collectors.collectingAndThen(Collectors.reducing(( wo1,wo2) -> wo1.getSeq().compareTo(wo2.getSeq()) < 0? wo1:wo2), Optional::get)));

                //通过产线查询当天计生产实绩
                List<MesOutPutStatistics> outPutStatisticsList = getMesOutPutStatistics(organizeCode, workCenterExtDb, workTime);

                //当前生产或待生产的启动工单
                MesWorkOrder mesWorkOrder = CollectionUtils.isEmpty(workOrderMap) || !workOrderMap.containsKey(workCenterExtDb.getWorkCenterCode()) ? null : workOrderMap.get(workCenterExtDb.getWorkCenterCode());

                //获取当前产线停开机记录
                MesShiftProdCenterRecord shiftProdCenterRecord = CollectionUtils.isEmpty(shiftProdCenterRecordMap) ? null : shiftProdCenterRecordMap.get(workCenterExtDb.getWorkCenterCode());

                // 无启动工单
                if((mesWorkOrder == null && CollectionUtils.isEmpty(outPutStatisticsList)) || (shiftProdCenterRecord == null)) {
                    continue;
                }

                //生产实绩
                double produceQty = outPutStatisticsList.stream().mapToDouble(MesOutPutStatistics::getQty).sum();
                model.setProduceQty(produceQty);

                //List<MesWorkOrderExt> orderExtList = getWorkOrderExtsContainReusePlanDatetime(workCenterCode, today, organizeCode);

                //计划数量
                Double sumQty = workOrderExtList.stream().filter(mesWorkOrderExt -> StringUtils.isEmpty(mesWorkOrderExt.getReusePlanDatetime())).map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);
                //复用计划数量
                Double reuseSumQty = workOrderExtList.stream().filter(mesWorkOrderExt -> !StringUtils.isEmpty(mesWorkOrderExt.getReusePlanDatetime())).map(MesWorkOrderExt::getReusePlanCompleteQty).reduce(0.00, Double::sum);
                model.setPlanQty(sumQty + reuseSumQty);

                //产能占比 = 生产实绩 / 计划数量 * 100%，取一位小数;
                double produceRate = MathOperation.div(produceQty, model.getPlanQty(), 3);
                model.setProduceRate(MathOperation.mul(produceRate, 100));

                if( produceQty != 0  || sumQty != 0){
                    requestList.add(model);
                }
            }
        }
        return requestList;
    }

    private List<MesShiftProdCenterRecord> getShiftProdCenterRecordByNow(List<String> workCenterCodes, String organizeCode) {
        DdlPackBean condition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList(workCenterCodes, MesExtConstWords.WORK_CENTER_CODE, condition);
        DdlPreparedPack.getTimeBetweenCol(TimeTool.getNowTime(true), MesExtConstWords.START_TIME, MesExtConstWords.END_TIME, condition, true);
        return shiftProdCenterRecordDao.findByHqlWhere(condition);
    }

    @Override
    public List<ProjectBadRateModel> queryBoardWorkCenterData(String organizeCode) throws ParseException {
        //返回集合
        List<ProjectBadRateModel> rateModels = null;
        //获取所有本体线信息
        List<MesWorkCenterExt> allWorkCenterExt = getAllWorkCenterExt(organizeCode);

        // 生产计划达成率
        MesBusiConfig workPlanTargetRateConfig = getWorkPlanTargetRate(organizeCode);
        // 生产计划达成率
        Double workPlanTargetRate = 0.0;
        if(workPlanTargetRateConfig != null){
            try {
                workPlanTargetRate = Double.valueOf(workPlanTargetRateConfig.getCfgValue());
            } catch (NumberFormatException e) {
                throw ImppExceptionBuilder.newInstance()
                        .setSystemID(CommonEnumUtil.SOFT_TYPE.MES.getCode())
                        .setErrorCode(ImppExceptionEnum.VARIFY_EXCEPTION.getCode())
                        .setErrorDetail("生产计划达成率维护数值格式有误！")
                        .build();
            }
        }

        if (!CollectionUtils.isEmpty(allWorkCenterExt)) {
            rateModels = new ArrayList<>();
            //遍历本体线  组装返回集合数据
            for (MesWorkCenterExt centerExt : allWorkCenterExt) {
                ProjectBadRateModel projectBadRateModel = new ProjectBadRateModel();
                //生产计划达成率
                projectBadRateModel.setProductPlanRate(workPlanTargetRate);
                //产线代码
                String workCenterCode = centerExt.getWorkCenterCode();
                projectBadRateModel.setWorkCenterCode(workCenterCode);
                //产线名称
                projectBadRateModel.setWorkCenterName(centerExt.getWorkCenterName());
                String shiftCode = centerExt.getShiftCode();
                //工单作业时间
                String workTime = centerExt.getWorkTime();
                if (StringUtils.isEmpty(workTime)) {
                    workTime = TimeTool.getToday();
                }

                //标准工时
                //标准作业时间 ：各产品当日实绩数量*产品标准工时然后进行汇总。
                double standardWorkTime = 0.0;

                //查询下线数据
                List<MesOutPutStatistics> outPutStatisticsList = getOutPutStatistics(workCenterCode, workTime, null, null, organizeCode);
                List<MesOutPutStatistics> outPutStatisticsListByShiftCode = CollectionUtils.isEmpty(outPutStatisticsList) ? new ArrayList<>(1) : outPutStatisticsList.stream().filter(mesOutPutStatistics -> mesOutPutStatistics != null && !StringUtils.isEmpty(mesOutPutStatistics.getShiftCode()) && mesOutPutStatistics.getShiftCode().equals(shiftCode)).collect(Collectors.toList());
//                 = getOutPutStatistics(workCenterCode, workTime, shiftCode, null, organizeCode);
                Map<String, List<MesOutPutStatistics>> snMapGroupByPartNo = outPutStatisticsListByShiftCode.stream().collect(Collectors.groupingBy(MesOutPutStatistics::getPartNo));
//                List<MesProduceSnExt> snExtList = getMesProduceSnExtsByShiftCode(workCenterCode, workTime, organizeCode,shiftCode);
//
//                Map<String, List<MesProduceSnExt>> snMapGroupByPartNo = snExtList.stream().collect(Collectors.groupingBy(MesProduceSnExt::getPartNo));

                for (Map.Entry<String, List<MesOutPutStatistics>> snListEntry : snMapGroupByPartNo.entrySet()) {
                    //物料编码
                    String partNo = snListEntry.getKey();
                    //物料信息
                    MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
                    //物料标准工数
                    Double standardWork = mesPartExt.getStandardWork();
                    if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
                        standardWork = 1.0;
                    }

                    //物料的完成数量（各产品当日实绩数量）
                    Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                    //产品标准工时
                    double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);

                    //各产品当日产品标准工时进行累加。
                    standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
                }

//                for (Map.Entry<String, List<MesProduceSnExt>> snListEntry : snMapGroupByPartNo.entrySet()) {
//                    //物料编码
//                    String partNo = snListEntry.getKey();
//                    //物料信息
//                    MesPartExt mesPartExt = getMesPartExt(partNo, organizeCode);
//                    //物料标准工数
//                    Double standardWork = mesPartExt.getStandardWork();
//                    if (BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == 0 || BigDecimal.valueOf(standardWork).compareTo(BigDecimal.ZERO) == -1) {
//                        standardWork = 1.0;
//                    }
//
//                    //物料的完成数量（各产品当日实绩数量）
//                    Double sumCompleteQtyByPartNo = snListEntry.getValue().stream().map(MesProduceSnExt::getQty).reduce(0.00, Double::sum);
//
//                    //产品标准工时
//                    double standardWorkTimeByPartNo = MathOperation.mul(sumCompleteQtyByPartNo, standardWork);
//
//                    //各产品当日产品标准工时进行累加。
//                    standardWorkTime = MathOperation.add(standardWorkTime, standardWorkTimeByPartNo);
//                }

                //当日实际生产
                Double sumCompleteQty = outPutStatisticsList.stream().map(MesOutPutStatistics::getQty).reduce(0.00, Double::sum);

                //当前产线停开机记录
                List<MesShiftProdCenterRecord> shiftProdCenterRecordList = getShiftProdCenterRecord(workCenterCode, shiftCode, workTime, organizeCode);

                //过滤停开机作业记录中 常规生产的数据（正常上班）
                List<MesShiftProdCenterRecord> conventionList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_PROD.getValue()))).collect(Collectors.toList());
                //当前常规作业时长（正常上班）
                Double conventionWorkTime = getServiceWorkTime(conventionList);

                //过滤停开机作业记录中 非常规生产的数据（加班上班）
                List<MesShiftProdCenterRecord> unConventionList = shiftProdCenterRecordList.stream().filter(
                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_PROD.getValue()))).collect(Collectors.toList());
                //当前非常规作业时长（加班上班）
                Double unConventionWorkTime = getServiceWorkTime(unConventionList);

                //过滤停开机作业记录中 非常规停机的数据（异常停机）
//                List<MesShiftProdCenterRecord> unnormalStopCenterList = shiftProdCenterRecordList.stream().filter(
//                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.UNNORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                //当前非常规停机时长（非作业时长）
//                Double unormalStopCenterTime = getServiceWorkTime(unnormalStopCenterList);

                //过滤停开机作业记录中 常规停机的数据（常规停机）
//                List<MesShiftProdCenterRecord> stopCenterList = shiftProdCenterRecordList.stream().filter(
//                        o -> (null != o && (o.getProdType() == MesExtEnumUtil.SHIFT_PROD_TYPE.NORMAL_STOP_CENTER.getValue()))).collect(Collectors.toList());
                //当前常规停机的数据（非作业时长）
//                Double stopCenterTime = getServiceWorkTime(stopCenterList);


                //总作业时间：(当前常规作业时长+当前非常规作业时长)-当前非常规停机时长
//                Double totalWorkTime = MathOperation.sub(MathOperation.add(conventionWorkTime, unConventionWorkTime), MathOperation.add(unormalStopCenterTime, stopCenterTime));
                //作业能率 = 标准作业时间/（勤务时间-非作业时间) * 100%,保留一位小数
                //作业能率 =标准作业时间/总作业时间*100%，保留一位小数
//                BigDecimal workRateBigDecimal = BigDecimal.valueOf(totalWorkTime);
//                BigDecimal workRate = workRateBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(workRateBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
//                projectBadRateModel.setWorkRate(workRate.doubleValue());

                //总勤务时间
                Double serviceWorkTime = MathOperation.add(conventionWorkTime, unConventionWorkTime);
                //综合能率：标准作业时间/勤务时间*100%，保留1位小数。
                BigDecimal serviceWorkTimeBigDecimal = BigDecimal.valueOf(serviceWorkTime);
                BigDecimal totalRate = serviceWorkTimeBigDecimal.compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(standardWorkTime).divide(serviceWorkTimeBigDecimal, 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                projectBadRateModel.setTotalRate(totalRate.doubleValue());

                //过滤当日下线中的所有工单
                List<String> outPutWoNoList = outPutStatisticsList.stream().map(MesOutPutStatistics::getWorkOrderNo).collect(Collectors.toList());
                List<MesRepairTask> repairTasks = getMesRepairTasksByTodayAndWoNo(outPutWoNoList, organizeCode);
                Double repairQty = repairTasks.stream().map(MesRepairTask::getRepairQty).reduce(0.00, Double::sum);
                //不良率 = 当日不良数量汇总/当日实绩汇总*100%，保留1位小数。
                if (BigDecimal.valueOf(sumCompleteQty).compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal defectiveRate = BigDecimal.valueOf(repairQty).compareTo(BigDecimal.ZERO) > 0 ? BigDecimal.valueOf(repairQty).divide(BigDecimal.valueOf(sumCompleteQty), 3, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
                    projectBadRateModel.setDefectiveRate(defectiveRate.doubleValue());
                } else {
                    projectBadRateModel.setDefectiveRate(0.0);
                }

                //当日实际生产
                projectBadRateModel.setProduceQty(sumCompleteQty.intValue());

                //当前日期
                String today = TimeTool.getToday();

                //通过产线查询当天计划数量
                //查询当天所有的有效工单
                List<MesWorkOrderExt> orderExtList = getWorkOrderExts(workCenterCode, today, organizeCode);

                //计划数量
                Double sumQty = orderExtList.stream().map(MesWorkOrderExt::getQty).reduce(0.00, Double::sum);
                projectBadRateModel.setPlanQty(sumQty.intValue());

                //产能占比=生产实绩/计划数量*100%，取一位小数;
                double produceRate = MathOperation.div(sumCompleteQty, sumQty, 3);
                // 在这该字段作为生成达成率
                projectBadRateModel.setWorkRate(MathOperation.mul(produceRate, 100));

                rateModels.add(projectBadRateModel);
            }

        }

        return rateModels;
    }

//    @Override
//    public List<ProjectBadRateModel> queryBoardWorkCenterData(String organizeCode) {
//
//        return null;
//    }

    private List<MesBusiConfig> getBusiConfigWorkCenterList(String organizeCode) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(MesExtConstWords.BOARD_WORK_SHOW_FLAG, MesExtConstWords.CFG_CODE, packBean);
        packBean.setOrderByStr(" order by cfgValueSeq asc ");
        return busiConfigRepository.findByHqlWhere(packBean);
    }

    private List<MesWorkCenterExt> getWorkCenterExtByCode(String organizeCode, List<String> workCenterCode) {
        DdlPackBean workCenterCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getInPackList( workCenterCode, MesExtConstWords.WORK_CENTER_CODE, workCenterCondition);
        return workCenterExtRepository.findByHqlWhere(workCenterCondition);
    }

    private List<MesOutPutStatistics> getMesOutPutStatistics(String organizeCode, MesWorkCenterExt centerExt, String today) {
        DdlPackBean packBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(centerExt.getWorkCenterCode(), MesExtConstWords.WORK_CENTER_CODE, packBean);
        DdlPreparedPack.getStringEqualPack(today, MesExtConstWords.WORK_TIME, packBean);
        List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRDao.findByHqlWhere(packBean);
        return outPutStatisticsList;
    }

    public List<MesWorkCenterExt> getAllWorkCenterExt(String organizeCode) {
        DdlPackBean workCenterCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(String.valueOf(MesExtEnumUtil.LINE_TYPE.ONTOLOGY_LINE.getValue()), "lineType", workCenterCondition);
        return workCenterExtRepository.findByHqlWhere(workCenterCondition);
    }

    public List<MesWorkOrderExt> getWorkOrderExts(String workCenterCode, String currentTime, String organizeCode) {
        DdlPackBean workOrderCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, workOrderCondition);
        //DdlPreparedPack.getNotInPack(MesExtEnumUtil.WORK_ORDER_STATUS.CREATE.getValue(), MesExtConstWords.WORK_ORDER_STATUS, workOrderCondition);
        //工单状态
        List<Integer> workOrderStatusList = new ArrayList<>();
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.LANDED.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.OPEN.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.PAUSE.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.CLOSE.getValue());

        DdlPreparedPack.getInPackList(workOrderStatusList, MesExtConstWords.WORK_ORDER_STATUS, workOrderCondition);
        DdlPreparedPack.getStringRightLikerPack(currentTime, MesExtConstWords.START_TIME, workOrderCondition);
        return workOrderExtRepository.findByHqlWhere(workOrderCondition);
    }

    public List<MesWorkOrderExt> getWorkOrderExtsContainReusePlanDatetime(String workCenterCode, String currentTime, String organizeCode) {
        DdlPackBean workOrderCondition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, workOrderCondition);
        //DdlPreparedPack.getNotInPack(MesExtEnumUtil.WORK_ORDER_STATUS.CREATE.getValue(), MesExtConstWords.WORK_ORDER_STATUS, workOrderCondition);
        //工单状态
        List<Integer> workOrderStatusList = new ArrayList<>();
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.LANDED.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.OPEN.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.PAUSE.getValue());
        workOrderStatusList.add(MesExtEnumUtil.WORK_ORDER_STATUS.CLOSE.getValue());

        DdlPreparedPack.getInPackList(workOrderStatusList, MesExtConstWords.WORK_ORDER_STATUS, workOrderCondition);
        //DdlPreparedPack.getStringRightLikerPack(currentTime, MesExtConstWords.START_TIME, workOrderCondition);
        workOrderCondition.addColumnQuery(MesExtConstWords.START_TIME, " and ( model." + MesExtConstWords.START_TIME + " like :m_" + MesExtConstWords.START_TIME, currentTime + "%");
        workOrderCondition.addColumnQuery(MesExtConstWords.REUSE_PLAN_DATE_TIME, " or model." + MesExtConstWords.REUSE_PLAN_DATE_TIME + " like :m_" + MesExtConstWords.REUSE_PLAN_DATE_TIME + " )", currentTime + "%");
        //DdlPreparedPack.getStringRightLikerPack(currentTime, MesExtConstWords.REUSE_PLAN_DATE_TIME, workOrderCondition);
        return workOrderExtRepository.findByHqlWhere(workOrderCondition);
    }

    public List<MesShiftProdCenterRecord> getShiftProdCenterRecord(String workCenterCode, String shiftCode, String workTime, String organizeCode) {
        DdlPackBean condition = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, MesExtConstWords.WORK_CENTER_CODE, condition);
        DdlPreparedPack.getStringEqualPack(shiftCode, MesExtConstWords.SHIFT_CODE, condition);
        DdlPreparedPack.getStringEqualPack(workTime, MesExtConstWords.WORK_TIME, condition);
        return shiftProdCenterRecordRepository.findByHqlWhere(condition);
    }

    /**
     * 获取两个时间中的每一天
     *
     * @param bigtimeStr
     * @param endTimeStr
     * @return
     * @throws ParseException
     */
    private List<String> getDayBetween(String bigtimeStr, String endTimeStr) {
        List<String> days = new LinkedList<>();
        try {
            Date bigtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(bigtimeStr + " 00:00:00");
            Date endtime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(endTimeStr + " 00:00:00");
            //定义一个接受时间的集合
            List<Date> lDate = new ArrayList<>();
            lDate.add(bigtime);
            Calendar calBegin = Calendar.getInstance();
            // 使用给定的 Date 设置此 Calendar 的时间
            calBegin.setTime(bigtime);
            Calendar calEnd = Calendar.getInstance();
            // 使用给定的 Date 设置此 Calendar 的时间
            calEnd.setTime(endtime);
            // 测试此日期是否在指定日期之后
            while (endtime.after(calBegin.getTime())) {
                // 根据日历的规则，为给定的日历字段添加或减去指定的时间量
                calBegin.add(Calendar.DAY_OF_MONTH, 1);
                lDate.add(calBegin.getTime());
            }

            for (Date date : lDate) {
                days.add(new SimpleDateFormat("yyyy-MM-dd").format(date));
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return days;
    }

    private List<MesOutPutStatistics> getOutPutStatistics(String workCenterCode, String workTime, String shiftCode, String partNo, String organizeCode) {
        DdlPackBean outPutStatisticsPackBean = DdlPackBean.getDdlPackBean(organizeCode);
        DdlPreparedPack.getStringEqualPack(workCenterCode, "workCenterCode", outPutStatisticsPackBean);
        DdlPreparedPack.getStringEqualPack(workTime, "workTime", outPutStatisticsPackBean);
        if (!StringUtils.isEmpty(shiftCode)) {
            DdlPreparedPack.getStringEqualPack(shiftCode, "shiftCode", outPutStatisticsPackBean);
        }
        if (!StringUtils.isEmpty(partNo)) {
            DdlPreparedPack.getStringEqualPack(partNo, "partNo", outPutStatisticsPackBean);
        }
        List<MesOutPutStatistics> outPutStatisticsList = outPutStatisticsRDao.findByHqlWhere(outPutStatisticsPackBean);
        return outPutStatisticsList;
    }

}
