package com.ximai.mes.pro.service.impl.task;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.StopWatch;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ximai.common.constant.UserConstants;
import com.ximai.common.utils.MessageUtils;
import com.ximai.common.utils.SecurityUtils;
import com.ximai.common.utils.data.DataUtil;
import com.ximai.common.utils.data.DateUtils;
import com.ximai.common.utils.data.ExceptionUtil;
import com.ximai.common.utils.data.StringUtils;
import com.ximai.mes.constant.*;
import com.ximai.mes.md.domain.MdItem;
import com.ximai.mes.md.domain.MdWorkstation;
import com.ximai.mes.md.domain.MdWorkunit;
import com.ximai.mes.md.mapper.MdItemMapper;
import com.ximai.mes.md.mapper.MdWorkstationMapper;
import com.ximai.mes.md.mapper.MdWorkunitMapper;
import com.ximai.mes.md.service.IMdWorkstationService;
import com.ximai.mes.md.service.IMdWorkunitService;
import com.ximai.mes.md.vo.MdItemVo;
import com.ximai.mes.pro.domain.*;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcess;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkOrderProcessTool;
import com.ximai.mes.pro.domain.proWorkOrder.ProWorkorder;
import com.ximai.mes.pro.domain.productionSolution.ProProductionSolution;
import com.ximai.mes.pro.domain.task.*;
import com.ximai.mes.pro.domain.vo.*;
import com.ximai.mes.pro.domain.vo.task.FeedbackValidateSerialNoParams;
import com.ximai.mes.pro.dto.task.ProTaskLinkFile;
import com.ximai.mes.pro.mapper.ProProcessMapper;
import com.ximai.mes.pro.mapper.ProProductionLogMapper;
import com.ximai.mes.pro.mapper.ProRouteMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkOrderProcessMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkOrderProcessToolMapper;
import com.ximai.mes.pro.mapper.proWorkOrder.ProWorkorderMapper;
import com.ximai.mes.pro.mapper.productionSolution.ProProductionSolutionMapper;
import com.ximai.mes.pro.mapper.task.ProTaskAssistProcessMapper;
import com.ximai.mes.pro.mapper.task.ProTaskMapper;
import com.ximai.mes.pro.mapper.task.ProTaskWorkorderMapper;
import com.ximai.mes.pro.mapper.task.ProTaskWorkunitMapper;
import com.ximai.mes.pro.schedule.AlgorithmDataSource;
import com.ximai.mes.pro.schedule.AlgorithmExtendDataSource;
import com.ximai.mes.pro.schedule.AlgorithmResultProcess;
import com.ximai.mes.pro.schedule.impl.BaoshenScheduleAlgorithmAdapter;
import com.ximai.mes.pro.schedule.strategy.EquipmentSelectionStrategyImpl;
import com.ximai.mes.pro.service.*;
import com.ximai.mes.pro.service.proWorkOrder.IProWorkorderService;
import com.ximai.mes.pro.service.task.IProTaskService;
import com.ximai.mes.pro.service.task.IProTaskWorkunitService;
import com.ximai.mes.qc.service.IQcIpqcService;
import com.ximai.mes.tm.domain.vo.TmToolRequestItemVo;
import com.ximai.mes.tm.service.ITmToolMachinesService;
import com.ximai.mes.tm.service.ITmToolRequestService;
import com.ximai.mes.wm.domain.WmProductRecpt;
import com.ximai.mes.wm.domain.WmProductRecptLine;
import com.ximai.mes.wm.service.IWmProductRecptLineService;
import com.ximai.mes.wm.service.IWmProductRecptService;
import com.ximai.system.mapper.SysUserMapper;
import com.ximai.system.strategy.AutoCodeUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

import static com.ximai.mes.constant.TaskWorkunitStatusEnum.BEGINNING;
import static com.ximai.mes.constant.TaskWorkunitStatusEnum.FINISHED;

/**
 * 生产任务Service业务层处理
 *
 * @date 2022-05-14
 */
@Service
public class ProTaskServiceImpl implements IProTaskService {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
    @Resource
    ProTaskAssistProcessMapper proTaskAssistProcessMapper;
    @Resource
    private ProTaskMapper proTaskMapper;
    @Autowired
    private ProTaskWorkorderMapper proTaskWorkorderMapper;
    @Autowired
    private IQcIpqcService qcIpqcService;
    @Resource
    private MdWorkunitMapper mdWorkunitMapper;
    @Autowired
    private IProTaskWorkunitService proTaskWorkunitService;
    @Autowired
    private ITmToolMachinesService tmToolMachinesService;
    @Autowired
    private ITmToolRequestService tmToolRequestService;
    @Autowired
    private IProMaterialRequestService iProMaterialRequestService;
    @Autowired
    private ProWorkorderMapper proWorkorderMapper;
    @Autowired
    private ProWorkOrderProcessMapper proWorkOrderProcessMapper;
    @Autowired
    private ProTaskWorkunitMapper proTaskWorkunitMapper;
    @Autowired
    private ProRouteMapper proRouteMapper;
    @Autowired
    private IWmProductRecptService wmProductRecptService;
    @Autowired
    private ProProcessMapper proProcessMapper;
    @Autowired
    private IProWorkorderService proWorkorderService;
    @Autowired
    private IWmProductRecptLineService wmProductRecptLineService;
    @Autowired
    private IProProcessService iProProcessService;
    @Autowired
    private AutoCodeUtil autoCodeUtil;
    @Autowired
    private MdItemMapper itemMapper;
    @Autowired
    private MdWorkstationMapper workstationMapper;
    @Autowired
    private IMdWorkstationService mdWorkstationService;
    @Autowired
    private ProProductionLogMapper proProductionLogMapper;
    @Autowired
    private ProWorkOrderProcessToolMapper proWorkOrderProcessToolMapper;
    @Autowired
    private IProFeedbackService proFeedbackService;
    @Resource
    private SysUserMapper sysUserMapper;
    @Autowired
    private IProStartWorkService proStartWorkService;
    @Autowired
    private ProFdQrcodePrintRecordServiceImpl proFdQrcodePrintRecordService;
    @Autowired
    private AlgorithmResultProcess algorithmResultProcess;
    @Autowired
    private AlgorithmDataSource algorithmDataSource;
    @Autowired
    private AlgorithmExtendDataSource equipmentNewestTaskAlgorithmData;
    @Autowired
    private AlgorithmExtendDataSource scheduleSetupRuleAlgorithmData;
    @Autowired
    private IProRecoilMaterialService proRecoilMaterialService;
    @Autowired
    private IProMaterialRequestService proMaterialRequestService;

    @Resource
    private IMdWorkunitService iMdWorkunitService;

    @Autowired
    ProProductionSolutionMapper proProductionSolutionMapper;

    /**
     * 查询生产任务
     *
     * @param taskId 生产任务主键
     * @return 生产任务
     */
    @Override
    public ProTask selectProTaskByTaskId(Long taskId) {
        return proTaskMapper.selectProTaskByTaskId(taskId);
    }

    @Override
    public ProTask getIpqcInsertInfo(String arrangeCode, Long workorderId, Long processId) {
        QueryWrapper<ProWorkOrderProcess> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(StringUtils.isNotEmpty(workorderId), "t3.workorder_id", workorderId);
        queryWrapper.eq(StringUtils.isNotEmpty(arrangeCode), "t3.arrange_code", arrangeCode);
        queryWrapper.eq(StringUtils.isNotEmpty(processId), "t1.process_id", processId);
        List<ProWorkOrderProcess> proWorkOrderProcesses = proWorkOrderProcessMapper.selectListByQw(queryWrapper);
        ProWorkOrderProcess proWorkOrderProcess = proWorkOrderProcesses.get(0);

        ProTask queryObj = new ProTask();
        queryObj.setWorkorderId(proWorkOrderProcess.getWorkorderId());
        queryObj.setProcessId(proWorkOrderProcess.getProcessId());
        queryObj.setProcessId(proWorkOrderProcess.getProcessId());
        QueryWrapper<ProTask> proTaskQueryWrapper = new QueryWrapper<>();
        proTaskQueryWrapper.eq(StringUtils.isNotEmpty(arrangeCode), "arrange_code", arrangeCode);
        proTaskQueryWrapper.eq(StringUtils.isNotEmpty(processId), "process_id", processId);
        List<ProTask> proTaskList = proTaskMapper.selectListByQw(proTaskQueryWrapper);
        ProTask task = proTaskList.get(0);
        task.setWorkorderId(proWorkOrderProcess.getWorkorderId());
        return task;
    }

    @Override
    public List<TmToolRequestItemVo> getToolOnProcessTemplate(ProTaskWorkunit proTaskWorkunit) {
        List<TmToolRequestItemVo> result = new ArrayList<>();
        ProTaskVo proTaskVo = new ProTaskVo();
        ProTask queryObj = new ProTask();
        queryObj.setTaskId(proTaskWorkunit.getTaskId());
        queryObj.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
        List<ProTask> proTaskList = proTaskMapper.selectProTaskDetailList(queryObj);
        if (CollectionUtil.isEmpty(proTaskList)) {
            return result;
        }

        proTaskVo = proTaskList.get(0).deepCopyObj(ProTaskVo.class);

        Long taskId = proTaskVo.getTaskId();
        Long processId = proTaskVo.getProcessId();
        Long taskWorkunitId = proTaskVo.getTaskWorkunitId();
        ProTaskWorkunit taskWorkunit = proTaskWorkunitService.selectProTaskWorkunitByTaskWorkunitId(taskWorkunitId);
//        int i = 0;
//        int requestNum = 0;
        //如果生产工单的工艺下没有设置工装夹具则不生成申请单
        Long workorderProcessId;


        //同过任务单id查询所有工单
        ProTaskWorkorder proTaskWorkorder = new ProTaskWorkorder();
        proTaskWorkorder.setTaskId(taskId);
        List<ProTaskWorkorder> proTaskWorkorders = proTaskWorkorderMapper.selectProTaskWorkorderList(proTaskWorkorder);
        if (CollectionUtil.isEmpty(proTaskWorkorders)) {
            return result;
        }

        List<Long> workOrderIdList = proTaskWorkorders.stream().map(ProTaskWorkorder::getWorkorderId).collect(Collectors.toList());
        List<ProWorkOrderProcess> proWorkOrderProcessVoList = new ArrayList<>();
        for (Long workOrderId : workOrderIdList) {
//            ProWorkOrderProcess proWorkOrderProcessVo = proWorkOrderProcessMapper.selectProWorkOrderProcessByProcessId(workOrderId, processId);//找到工单工序
            QueryWrapper<ProWorkOrderProcess> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("t1.workorder_id", workOrderId);
            queryWrapper.eq("t1.process_id", processId);
            List<ProWorkOrderProcess> proWorkOrderProcesses = proWorkOrderProcessMapper.selectListByQw(queryWrapper);
            ProWorkOrderProcess proWorkOrderProcess = proWorkOrderProcesses.get(0);

            if (proWorkOrderProcess != null) {
                proWorkOrderProcessVoList.add(proWorkOrderProcess);
            }
        }

        if (CollectionUtil.isEmpty(proWorkOrderProcessVoList)) {
            return result;
        }

        if (CollectionUtil.isEmpty(proWorkOrderProcessVoList)) {
            return result;
        }

        List<ProWorkOrderProcessTool> proWorkOrderProcessTools = new ArrayList<>();
        for (ProWorkOrderProcess proWorkOrderProcessVo : proWorkOrderProcessVoList) {
            workorderProcessId = proWorkOrderProcessVo.getWorkorderProcessId();
            List<ProWorkOrderProcessTool> proWorkOrderProcessToolsList = proWorkOrderProcessToolMapper.selectProWorkOrderProcessToolByWorkorderProcessId(workorderProcessId);
            proWorkOrderProcessTools.addAll(proWorkOrderProcessToolsList);
        }

        if (CollectionUtil.isNotEmpty(proWorkOrderProcessTools)) {
            //根据tool_id进行判重，只保留要求数量最大的
            Map<Long, ProWorkOrderProcessTool> toolIdAndProcessToolMap = new HashMap<>();//tool_id,工装对象
            for (ProWorkOrderProcessTool proWorkOrderProcessTool : proWorkOrderProcessTools) {
                if (BeanUtil.isEmpty(toolIdAndProcessToolMap.get(proWorkOrderProcessTool.getToolId()))) {
                    toolIdAndProcessToolMap.put(proWorkOrderProcessTool.getToolId(), proWorkOrderProcessTool);
                } else {
                    ProWorkOrderProcessTool proWorkOrderProcessToolMap = toolIdAndProcessToolMap.get(proWorkOrderProcessTool.getToolId());
                    if (proWorkOrderProcessToolMap.getQuantity().compareTo(proWorkOrderProcessTool.getQuantity()) < 0) {//当map中的数量小于时，将新的替换
                        toolIdAndProcessToolMap.put(proWorkOrderProcessTool.getToolId(), proWorkOrderProcessTool);
                    }
                }
            }


            Set<Long> toolIds = toolIdAndProcessToolMap.keySet();
            for (Long toolId : toolIds) {
                ProWorkOrderProcessTool proWorkOrderProcessTool = toolIdAndProcessToolMap.get(toolId);
                TmToolRequestItemVo tmToolRequestItemVo = new TmToolRequestItemVo();
                tmToolRequestItemVo.setItemName(proWorkOrderProcessTool.getItemName());
                tmToolRequestItemVo.setItemId(proWorkOrderProcessTool.getToolId());
                tmToolRequestItemVo.setAllQuantity(proWorkOrderProcessTool.getQuantity().intValue());
                tmToolRequestItemVo.setNextMaintenPeriod(taskWorkunit.getQuantity().intValue());
                result.add(tmToolRequestItemVo);
            }
            return result;
        } else {
            return result;
        }
    }


    @Override
    public List<Map<String, String>> listMdItemByWorkUnit(Long id) {
        ArrayList<Map<String, String>> result = new ArrayList<>();
        ProTask proTask = this.selectProTaskByTaskId(id);
        if (proTask == null) {
            return result;
        }

        ProTaskVo proTaskVo = new ProTaskVo();
        if (StringUtils.isNotNull(proTask)) {
            BeanUtils.copyProperties(proTask, proTaskVo);
        }

        Long taskId = proTaskVo.getTaskId();
        Long processId = proTaskVo.getProcessId();

//        int i = 0;
//        int requestNum = 0;
        //如果生产工单的工艺下没有设置工装夹具则不生成申请单
        Long workorderProcessId;
        //同过任务单id查询所有工单
        ProTaskWorkorder proTaskWorkorder = new ProTaskWorkorder();
        proTaskWorkorder.setTaskId(taskId);
        List<ProTaskWorkorder> proTaskWorkorders = proTaskWorkorderMapper.selectProTaskWorkorderList(proTaskWorkorder);
        if (CollectionUtil.isEmpty(proTaskWorkorders)) {
            return result;
        }
        List<Long> workOrderIdList = proTaskWorkorders.stream().map(ProTaskWorkorder::getWorkorderId).collect(Collectors.toList());
        List<ProWorkOrderProcess> proWorkOrderProcessVoList = new ArrayList<>();
        for (Long workOrderId : workOrderIdList) {
            QueryWrapper<ProWorkOrderProcess> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("t1.workorder_id", workOrderId);
            queryWrapper.eq("t1.process_id", processId);
            List<ProWorkOrderProcess> proWorkOrderProcesses = proWorkOrderProcessMapper.selectListByQw(queryWrapper);
            ProWorkOrderProcess proWorkOrderProcess = proWorkOrderProcesses.get(0);
            proWorkOrderProcessVoList.add(proWorkOrderProcess);
        }
        if (CollectionUtil.isEmpty(proWorkOrderProcessVoList)) {
            return result;
        }

        List<ProWorkOrderProcessTool> proWorkOrderProcessTools = new ArrayList<>();
        for (ProWorkOrderProcess proWorkOrderProcessVo : proWorkOrderProcessVoList) {
            workorderProcessId = proWorkOrderProcessVo.getWorkorderProcessId();
            List<ProWorkOrderProcessTool> proWorkOrderProcessToolsList = proWorkOrderProcessToolMapper.selectProWorkOrderProcessToolByWorkorderProcessId(workorderProcessId);
            proWorkOrderProcessTools.addAll(proWorkOrderProcessToolsList);
        }

        if (CollectionUtil.isNotEmpty(proWorkOrderProcessTools)) {
            //根据tool_id进行判重，只保留要求数量最大的
            Map<Long, ProWorkOrderProcessTool> toolIdAndProcessToolMap = new HashMap<>();//tool_id,工装对象
            for (ProWorkOrderProcessTool proWorkOrderProcessTool : proWorkOrderProcessTools) {
                if (BeanUtil.isEmpty(toolIdAndProcessToolMap.get(proWorkOrderProcessTool.getToolId()))) {
                    toolIdAndProcessToolMap.put(proWorkOrderProcessTool.getToolId(), proWorkOrderProcessTool);
                } else {
                    ProWorkOrderProcessTool proWorkOrderProcessToolMap = toolIdAndProcessToolMap.get(proWorkOrderProcessTool.getToolId());
                    if (proWorkOrderProcessToolMap.getQuantity().compareTo(proWorkOrderProcessTool.getQuantity()) < 0) {//当map中的数量小于时，将新的替换
                        toolIdAndProcessToolMap.put(proWorkOrderProcessTool.getToolId(), proWorkOrderProcessTool);
                    }
                }
            }


            Set<Long> toolIds = toolIdAndProcessToolMap.keySet();
            for (Long toolId : toolIds) {
                MdItem mdItem = new MdItem();
                ProWorkOrderProcessTool proWorkOrderProcessTool = toolIdAndProcessToolMap.get(toolId);

                mdItem.setItemId(toolId);
                List<MdItemVo> list = itemMapper.selectMdItemList(mdItem);
                MdItemVo mdItemVo = list.get(0);
                Map<String, String> map = new HashMap<>();
                map.put("itemId", proWorkOrderProcessTool.getToolId().toString());
                map.put("itemName", mdItemVo.getItemName());
                map.put("AllQuantity", "1");
                map.put("nextMaintenPeriod", proWorkOrderProcessTool.getQuantity().toString());
                result.add(map);
            }
            return result;
        } else {
            return result;
        }
    }

    @Override
    public ProTask selectProTaskByTaskCode(String taskCode) {
        return proTaskMapper.selectProTaskByTaskCode(taskCode);
    }


    /**
     * 查询生产任务列表
     *
     * @param proTask 生产任务
     * @return 生产任务
     */
    @Override
    public List<ProTask> selectProTaskList(ProTask proTask) {
        return proTaskMapper.selectProTaskList(proTask);
    }

    @Override
    public ProTask selectByArrangeCodeAndProcessId(String arrangeCode, Long processId) {
        return proTaskMapper.selectByArrangeCodeAndProcessId(arrangeCode, processId);
    }


    /**
     * 查询生产任务列表
     *
     * @param proTask 生产任务
     * @return 生产任务
     */
    @Override
    public List<ProTask> selectProTaskDetailList(ProTask proTask) {

        List<ProTask> proTasks1 = proTaskMapper.selectProTaskDetailList(proTask);
        List<ProTask> proTasks = proTasks1.stream().filter(s -> !s.getStatus().equals("FINISHED")).collect(Collectors.toList());

        List<ProTask> objects = null;
        if (StringUtils.isNotEmpty(proTask.getWorkorderCode())) {
            Set<String> arrangeCodes = proTasks.stream().map(ProTask::getArrangeCode).filter(Objects::nonNull).collect(Collectors.toSet());
            QueryWrapper<ProWorkorder> proWorkorderQueryWrapper = new QueryWrapper<>();
            proWorkorderQueryWrapper.in("arrange_code", arrangeCodes);
            proWorkorderQueryWrapper.eq("workorder_code", proTask.getWorkorderCode());
            List<ProWorkorder> proWorkorders = proWorkorderMapper.selectListByQw(proWorkorderQueryWrapper);
            objects = new ArrayList<>();
            if (CollectionUtil.isNotEmpty(proWorkorders)) {
                ProWorkorder proWorkorder = proWorkorders.get(0);
                String arrangeCode = proWorkorder.getArrangeCode();
                String workorderCode = proWorkorder.getWorkorderCode();
                for (ProTask task : proTasks) {
                    if (Objects.equals(task.getArrangeCode(), arrangeCode)) {
                        task.setWorkorderCode(workorderCode);
                        objects.add(task);
                    }
                }
            }
        }
        return objects != null ? objects : proTasks;
    }

    @Override
    public List<ProTask> selectProTaskJoinTaskWorkUnit(QueryWrapper<ProTask> proTask) {
        return proTaskMapper.selectProTaskJoinTaskWorkUnit(proTask);
    }

    @Override
    public List<ProTaskVo> selectProTaskJoinWorkorder(QueryWrapper<ProTask> proTask) {
        return proTaskMapper.selectProTaskJoinWorkorder(proTask);
    }

    /**
     * 新增生产任务
     *
     * @param proTask 生产任务
     * @return 结果
     */
    @Override
    public int insertProTask(ProTask proTask) {
        proTask.createAction();
        proTask.setTaskCode(autoCodeUtil.genSerialCode(UserConstants.TASK_CODE, null));
        return proTaskMapper.insertProTask(proTask);
    }

    @Override
    public int createProTask(ProTask proTask) {
        if (proTask.getQuantity().compareTo(BigDecimal.ZERO) != 1) {
            throw new RuntimeException("排产数量必须大于0！");
        }

        if (!StringUtils.isNotNull(proTask.getWorkstationId())) {
            throw new RuntimeException("请选择工作站！");
        }

        if (proTask.getDuration() <= 0) {
            throw new RuntimeException("生产时长必须大于0！");
        }

        //生产工单
        ProWorkorderQuery proWorkorderQuery = new ProWorkorderQuery();
        proWorkorderQuery.setArrangeCode(proTask.getArrangeCode());
        List<ProWorkorder> workorders = proWorkorderService.selectProWorkorderList(proWorkorderQuery);
        ProWorkorder order = workorders.get(0);
        proTask.setItemId(order.getProductId());
        proTask.setItemCode(order.getProductCode());
        proTask.setItemName(order.getProductName());
        proTask.setSpecification(order.getProductSpc());
        proTask.setUnitOfMeasure(order.getUnitOfMeasure());
        proTask.setClientId(order.getClientId());
        proTask.setClientCode(order.getClientCode());
        proTask.setClientName(order.getClientName());

        //工序信息
        ProProcess process = iProProcessService.selectProProcessByProcessId(proTask.getProcessId());
        if (StringUtils.isNotNull(process)) {
            proTask.setProcessId(process.getProcessId());
            proTask.setProcessCode(process.getProcessCode());
            proTask.setProcessName(process.getProcessName());
        } else {
            throw new RuntimeException("当前生产任务对应的工序信息无效！" + proTask.getProcessId());
        }

        //自动生成任务编号和名称
        proTask.setTaskName(proTask.getItemName() + "【" + proTask.getQuantity().toString() + "】" + proTask.getUnitOfMeasure());
        return this.insertProTask(proTask);
    }

    /**
     * 修改生产任务
     *
     * @param proTask 生产任务
     * @return 结果
     */
    @Override
    public int updateProTask(ProTask proTask) {
        ProTask proTaskInfo = this.selectProTaskByTaskId(proTask.getTaskId());
        ProProductionLog proProductionLog = new ProProductionLog();
        proProductionLog.setTaskId(proTaskInfo.getTaskId());
        proProductionLog.setWorkstationId(proTaskInfo.getWorkstationId());
        proProductionLog.setOperatorId(SecurityUtils.getUserId());
        proProductionLog.setOperatorName(SecurityUtils.getUsername());
        proProductionLog.setOperatorTime(DateUtils.getNowDate());
        proProductionLog.setStatus(proTaskInfo.getStatus());
        proProductionLog.setFaultDescription(proTaskInfo.getAttr1());
        proProductionLog.createAction();
        proProductionLogMapper.insertProProductionLog(proProductionLog);

        proTask.updateAction();
        return proTaskMapper.updateProTask(proTask);
    }

    /**
     * 批量删除生产任务
     *
     * @param taskIds 需要删除的生产任务主键
     * @return 结果
     */
    @Override
    public int deleteProTaskByTaskIds(Long[] taskIds) {
        return proTaskMapper.deleteProTaskByTaskIds(taskIds);
    }

    /**
     * 删除生产任务信息
     *
     * @param taskId 生产任务主键
     * @return 结果
     */
    @Override
    public int deleteProTaskByTaskId(Long taskId) {
        return proTaskMapper.deleteProTaskByTaskId(taskId);
    }

    /**
     * 新增任务单/合并任务单
     */
    @Override
    public int insertProTasks(Long[] workorderIds) {
        List<ProWorkorder> proWorkorderList = proWorkorderMapper.selectProWorkorderGorupArrangeByWorkorderIds(workorderIds);

        //工单按编排单分组
        Map<Object, List<ProWorkorder>> workordersGroupedByArrangeCode = proWorkorderList.stream()
                .collect(Collectors.groupingBy(ProWorkorder::getArrangeCode));
        for (Map.Entry<Object, List<ProWorkorder>> entry : workordersGroupedByArrangeCode.entrySet()) {
            BigDecimal quantity = BigDecimal.valueOf(0);
            List<ProWorkorder> workorderList = entry.getValue();

            for (ProWorkorder proWorkorder : workorderList) {
                if (!StringUtils.isNotNull(proWorkorder)) {
                    return 4;
                }
                if (proWorkorder.getQuantity().compareTo(BigDecimal.ZERO) != 1) {
                    return 5;
                }
                if (!StringUtils.isNotNull(proWorkorder.getRequestDate()) && proWorkorder.getRequestDate().before(DateUtils.getNowDate())) {
                    return 9;
                }
                quantity = quantity.add(proWorkorder.getQuantity());
            }

            if (quantity.compareTo(BigDecimal.ZERO) != 1) {
                return 6;
            }

            // 获取第一个作为模板数据
            ProWorkorder proWorkorder = workorderList.get(0);
            Long workorderId = proWorkorder.getWorkorderId();
            String arrangeCode = proWorkorder.getArrangeCode();

            // 获取工序列表
            QueryWrapper<ProWorkOrderProcessVo> query = new QueryWrapper<>();
            query.eq("pwop.workorder_id", workorderId);
            List<ProWorkOrderProcessVo> proWorkOrderProcessVoList = proWorkOrderProcessMapper.selectProWorkOrderProcess(query);
            if (proWorkOrderProcessVoList.isEmpty()) {
                return 7;
            }

            // 根据工序创建任务单
            int i = 1;
            for (ProWorkOrderProcessVo proWorkOrderProcessVo : proWorkOrderProcessVoList) {
                // 验证工序
                ProProcess proProcess = proProcessMapper.selectProProcessByProcessId(proWorkOrderProcessVo.getProcessId());
                if (!StringUtils.isNotNull(proProcess)) {
                    return 8;
                }

                ProTask proTask = new ProTask();
                // 封装
                proTask.setWorkstationId(proWorkOrderProcessVo.getWorkstationId());
                proTask.setProcessId(proWorkOrderProcessVo.getProcessId());
                proTask.setItemId(proWorkorder.getProductId());
                proTask.setSpecification(proWorkorder.getProductSpc());
                proTask.setUnitOfMeasure(proWorkorder.getUnitOfMeasure());
                proTask.setQuantity(quantity);
                proTask.setOrdinal(i);
                //首工序，待加工数等于排产数
                if (i == 1) {
                    proTask.setQuantityWait(quantity);
                } else {
                    proTask.setQuantityWait(BigDecimal.ZERO);
                }

                //末道工序
                if (i == proWorkOrderProcessVoList.size()) {
                    proTask.setIsLastProcess(1);
                } else {
                    proTask.setIsLastProcess(0);
                }
                proTask.setColorCode(proWorkOrderProcessVo.getColorCode());
                proTask.setStatus(TaskStatusEnum.PREPARE.getStatus()); // 设置状态为草稿(待确认)
                proTask.setArrangeCode(arrangeCode);
                proTask.setTaskBatch(arrangeCode + "-001");
                //自动生成任务编号和名称
                MdItem mdItem = itemMapper.selectMdItemById(proWorkorder.getProductId());
                proTask.setTaskName(mdItem.getItemName() + "【" + proTask.getQuantity().toString() + "】" + proTask.getUnitOfMeasure());

                // 保存
                this.insertProTask(proTask);
                Long taskId = proTask.getTaskId();

                // 保存到合并表
                for (ProWorkorder workorder : workorderList) {
                    ProTaskWorkorder proTaskWorkorder = new ProTaskWorkorder();
                    proTaskWorkorder.setTaskId(taskId);
                    proTaskWorkorder.setIdx((long) i);
                    proTaskWorkorder.setWorkorderId(workorder.getWorkorderId());
                    // 保存
                    proTaskWorkorderMapper.insertProTaskWorkorder(proTaskWorkorder);
                }
                i++;
            }

            long[] workorderIdArr = workorderList.stream()
                    .mapToLong(ProWorkorder::getWorkorderId)
                    .toArray();

            // 修改工单状态 -- 已生成任务单
            for (Long id : workorderIdArr) {
                //生成编排单号
                ProWorkorder proWorkorderUpdate = new ProWorkorder();
                proWorkorderUpdate.setStatus(WorkorderStatusEnum.ISSUED.getValue());
                proWorkorderUpdate.setArrangeCode(arrangeCode);
                proWorkorderUpdate.setWorkorderId(id);
                proWorkorderMapper.updateProWorkorder(proWorkorderUpdate);
            }
        }

        return 1;
    }

    /**
     * 返回甘特图对象
     *
     * @return
     */
    @Override
    public GanttTask getGanttTaskList() {
        GanttTask ganttTask = new GanttTask();
        List<GanttData> ganttData = new ArrayList<GanttData>();
        List<GanttLink> ganttLinks = new ArrayList<GanttLink>();

        // 当前时间
        Date nowDate = DateUtils.getNowDate();

        // 获取所有工作站信息
        MdWorkstation workstationQ = new MdWorkstation();
        workstationQ.setEnableFlag("Y");
        List<MdWorkstation> workstationList = workstationMapper.selectMdWorkstationList(workstationQ);
        if (!StringUtils.isNotNull(workstationList)) {
            return null;
        }

        // 遍历工作站信息
        for (MdWorkstation workstation : workstationList) {

            GanttData workstationData = new GanttData();
            workstationData.setId("MD" + workstation.getWorkstationId());
            workstationData.setType(UserConstants.GANTT_TASK_TYPE_PROJECT);
            workstationData.setText(workstation.getWorkstationName());

            // 查询工作站下的所有任务单
            ProTask proTask = new ProTask();
            proTask.setWorkstationId(workstation.getWorkstationId());
            BigDecimal quantity = BigDecimal.valueOf(0); // 工作站的生产数量
            BigDecimal quantityProduced = BigDecimal.valueOf(0); // 工作站已生产数量
            Date endDate = nowDate; // 工作站的最晚结束时间
            Date startDate = nowDate; // 工作站的最早开始时间
            Date date = new Date();

            // 基于时间查询--结束时间晚于当前时间
            proTask.setEndTime(new Date());
            proTask.setStatus(TaskStatusEnum.PREPARE.getStatus());
            List<ProTask> proTaskList = proTaskMapper.selectProTaskList(proTask);
            if (proTaskList.size() == 0) {
                continue;
            }

            for (ProTask task : proTaskList) {
                GanttData taskData = new GanttData();
                taskData.setId("MD" + task.getTaskId());
                taskData.setParent("MD" + workstation.getWorkstationId()); // 将工作站id设置为父id
                taskData.setColor(task.getColorCode()); // 设置甘特图颜色
                taskData.setType(UserConstants.GANTT_TASK_TYPE_TASK);
                BigDecimal taskQuantity = task.getQuantity();
                BigDecimal taskQuantityProduced = task.getQuantityProduced();
                quantity = quantity.add(taskQuantity); // 添加到工作站总排产数量中
                quantityProduced = quantityProduced.add(taskQuantityProduced); // 添加到工作站总已生产数量中
                taskData.setProgress(taskQuantityProduced.divide(taskQuantity, RoundingMode.HALF_UP).floatValue()); // 设置生产进度
                Date end_date = task.getEndTime();
                // 比较结束时间
                if (endDate.before(end_date)) {
                    endDate = end_date;
                }
                taskData.setText(task.getItemName() + taskQuantity.stripTrailingZeros().toPlainString() + task.getUnitOfMeasure()); // 默认使用“[产品]+[数量]+[单位]”格式。
                taskData.setWorkstation(taskData.getWorkstation());
                taskData.setQuantity(taskQuantity);
                Date startTime = task.getStartTime();
                // 比较开始时间
                if (startTime.before(startDate)) {
                    startDate = startTime;
                }
                taskData.setStart_date(startTime);
                taskData.setDuration(task.getDuration());
                taskData.setEnd_date(end_date);
                taskData.setProcess(task.getProcessName());
                taskData.setProduct(task.getItemName());

                ganttData.add(taskData);
            }
            // 计算工作站的生产时长及生产进度
            Long duration = (endDate.getTime() - nowDate.getTime()) / 1000 / 60 / 60; // 单位小时
            workstationData.setDuration(duration);
            workstationData.setProgress(quantityProduced.divide(quantity, RoundingMode.HALF_UP).floatValue());
            workstationData.setQuantity(quantity);
            workstationData.setEnd_date(endDate);
            workstationData.setStart_date(startDate);
            workstationData.setWorkstation(workstation.getWorkstationName());
            ganttData.add(workstationData);
        }

        ganttTask.setData(ganttData);
        ganttTask.setLinks(ganttLinks);
        return ganttTask;
    }

    @Override
    public void setStatus(Long taskId, String issuegenerated) {
        proTaskMapper.updateProTaskStatus(taskId, issuegenerated);
    }

    @Override
    public List<String> getWorkorderNos(Long taskId) {
        QueryWrapper<ProTask> query = new QueryWrapper<>();
        query.eq("t1.task_id", taskId);
        List<ProTaskVo> list = proTaskMapper.selectProTaskJoinWorkorder(query);
        return list.stream().map(s -> s.getWorkorderCode()).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public List<ProPackagePrintResult> feedBack(ProFeedback feedback) {
        List<ProPackagePrintResult> response = new ArrayList<>();
        BigDecimal feedbackQualifyConst = feedback.getQuantityQualify();
        BigDecimal fuantityUnqualify = feedback.getQuantityUnqualify();
        //温志超修改 ：合格和非合格数量都不允许小于0
        ExceptionUtil.checkTrueThrowException( (feedbackQualifyConst.compareTo(BigDecimal.ZERO) < 0 || fuantityUnqualify.compareTo(BigDecimal.ZERO) < 0),
                MessageUtils.message("pro.feedback.error.min.quantity"));

        ExceptionUtil.checkTrueThrowException((feedbackQualifyConst.compareTo(BigDecimal.ZERO) <= 0 && fuantityUnqualify.compareTo(BigDecimal.ZERO) <= 0),
                 "报工数目合格、不合格数不能都小于等于0");
        if(StringUtils.isNotEmpty(feedback.getQrcode())){
            FeedbackValidateSerialNoParams feedbackValidateSerialNoParams = new FeedbackValidateSerialNoParams();
            feedbackValidateSerialNoParams.setQrcode(feedback.getQrcode());
            feedbackValidateSerialNoParams.setTaskWorkunitId(feedback.getTaskWorkunitId());
            proFeedbackService.validateSerialNo(feedbackValidateSerialNoParams);
        }

        ProTaskWorkunit taskWorkunit = proTaskWorkunitService.selectProTaskWorkunitByTaskWorkunitId(feedback.getTaskWorkunitId());
        ExceptionUtil.checkTrueThrowException(!taskWorkunit.getStatus().equals(TaskStatusEnum.BEGINNING.getStatus()), MessageUtils.message("pro.feedback.error.before.start"));

        //检索已经报工的数量
        double execQuantityQualifySumConst = proFeedbackService.selectQuantityQualifySum(new ProFeedback(null, null, null, taskWorkunit.getTaskWorkunitId()));

        ProTask task = this.selectProTaskByTaskId(feedback.getTaskId());
        BigDecimal taskQuantityWaitConst = task.getQuantityWait();

        double taskQuantityWaitDouConst = taskQuantityWaitConst.doubleValue();
        double feedbackQualityDouConst = feedbackQualifyConst.doubleValue();

        BigDecimal quantityWaitVal = BigDecimal.ZERO;
        BigDecimal feedbackQualityVal = BigDecimal.valueOf(feedbackQualityDouConst);
        Long workorderId = feedback.getWorkorderId();

        QueryWrapper<ProWorkorder> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("t1.workorder_code", task.getArrangeCode());
        queryWrapper.notIn("t1.status", Arrays.asList(WorkorderStatusEnum.CLOSE.getValue(), WorkorderStatusEnum.CANCEL.getValue(), WorkorderStatusEnum.CANCELED.getValue()));
        List<ProWorkorder> proWorkorders = proWorkorderService.selectListByQw(queryWrapper);
        double maxWorkunitQuantityConst = taskWorkunit.getQuantity().doubleValue();
        //检查该工单绑定的生产版本是否允许超报,PS只有首工序允许
        if(taskQuantityWaitConst.compareTo(feedbackQualifyConst.add(fuantityUnqualify)) < 0){
            if(task.getOrdinal() == 1){
                if(proWorkorders.size() > 0 && proWorkorders.get(0).getProductionSolutionId() != null){
                    ProProductionSolution proProductionSolution
                            = proProductionSolutionMapper.selectProProductionSolutionByProductionSolutionId(proWorkorders.get(0).getProductionSolutionId());
                    if(proProductionSolution != null && proProductionSolution.getSurpassState() != null){
                        if(!proProductionSolution.getSurpassState()){
                            //不允许超报 可报工数目 - (合格数 + 不合格数）不能小于 0
                            ExceptionUtil.checkTrueThrowException(
                                    taskQuantityWaitConst.compareTo(feedbackQualifyConst.add(fuantityUnqualify)) < 0, "工单关联的生产版本不允许超报行为");
                        }
                    }
                }
            }else{
                ExceptionUtil.checkTrueThrowException(true, "非首工序不允许超过可报工数报工");
            }
        }

        //本次合格数和不合格数总和大于可报工数目 与 已报工数目已经超过了排产数量
        if ((feedbackQualityDouConst + fuantityUnqualify.doubleValue())>= task.getQuantityWait().doubleValue() &&  task.getQuantity().doubleValue() <= (execQuantityQualifySumConst + feedbackQualityDouConst + fuantityUnqualify.doubleValue())) {
            taskWorkunit.setStatus(FINISHED.getStatus());
        }
        quantityWaitVal = taskQuantityWaitConst.subtract(feedbackQualityVal.add(fuantityUnqualify));

        task.setQuantityWait(quantityWaitVal);
        task.setQuantityProduced(DataUtil.getNormalData(task.getQuantityProduced()).add(feedbackQualityVal).add(fuantityUnqualify));
        task.setQuantityQualify(DataUtil.getNormalData(task.getQuantityQualify()).add(feedbackQualityVal));

        taskWorkunit.setQuantityProduced(DataUtil.getNormalData(taskWorkunit.getQuantityProduced()).add(feedbackQualityVal).add(fuantityUnqualify));
        taskWorkunit.setQuantityQualify(DataUtil.getNormalData(taskWorkunit.getQuantityQualify()).add(feedbackQualityVal));


        task.setQuantityUnqualify(DataUtil.getNormalData(task.getQuantityUnqualify()).add(feedback.getQuantityUnqualify()));
        taskWorkunit.setQuantityUnqualify(DataUtil.getNormalData(taskWorkunit.getQuantityUnqualify()).add(feedback.getQuantityUnqualify()));

        List<MdWorkstation> mdWorkstations = workstationMapper.selectListByQw(new QueryWrapper<MdWorkstation>().eq("workstation_id", feedback.getWorkstationId()));
        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(mdWorkstations), MessageUtils.message( "md.workStation.error.not.exist"));

        MdWorkstation workstation = mdWorkstations.get(0);
        feedback.setWorkstationCode(workstation.getWorkstationCode());
        feedback.setWorkstationName(workstation.getWorkstationName());
        feedback.setWorkstationId(DataUtil.repliceData(feedback.getWorkstationId(), workstation.getWorkstationId()));
        feedback.setFeedbackType("SELF");
        feedback.setWorkunitId(taskWorkunit.getWorkunitId());
        feedback.setNickName(sysUserMapper.selectUserById(SecurityUtils.getUserId()).getNickName());

        //暂停更新记录
        if (Objects.equals(taskWorkunit.getStatus(), FINISHED.getStatus())) {
            proStartWorkService.closeObj(feedback);
        } else {
            proStartWorkService.updateObj(feedback);
        }
        //按派工表保存报工记录
        LinkedHashMap<String, ProFeedbackSplitInfo> feedbackWorkorder = proFeedbackService.taskFeedback(task, feedback);
        //查询关联下道工序
        ProTask nextTask = this.getNextTaskByTaskId(feedback.getTaskId());
        if (nextTask != null) {
            // 下道任务待加工数累加合格数量
            nextTask.setQuantityWait(DataUtil.getNormalData(nextTask.getQuantityWait()).add(feedbackQualifyConst));
            List<ProTaskWorkunit> proTaskWorkunits = proTaskWorkunitMapper.selectListByQw(new QueryWrapper<ProTaskWorkunit>().eq("task_id", nextTask.getTaskId()));
            proTaskWorkunits.stream().filter(x -> Objects.equals(x.getStatus(), FINISHED.getStatus())).forEach(x -> {
                x.setStatus(TaskWorkunitStatusEnum.PREPARE.getStatus());
                proTaskWorkunitMapper.updateProTaskWorkunit(x);
            });
            nextTask.setStatus(TaskStatusEnum.PREPARE.getStatus());
            this.updateProTask(nextTask);
        }
        this.updateProTask(task);
        if (feedbackQualityVal.doubleValue() > 0) {
            //查询关联下道工序
            //如果为最后一道工序，回写工单数量
            if (StringUtils.isEmpty(nextTask)) {
                feedbackWorkorder.forEach((k, v) -> {
                    proWorkorderService.reportUpdateProWorkorder(v.getWorkorder(), v.getQuantityQualify(), v.getQuantityUnqualify());
                });
            }
        }
        proTaskWorkunitService.updateProTaskWorkunit(taskWorkunit);
        return response;
    }



    @Transactional
    @Override
    public void changeStatus(ProTask proTask) {
        Long taskWorkunitId = proTask.getTaskWorkunitId();

        // 更新派工单状态
        ProTaskWorkunit proTaskWorkunit = proTaskWorkunitMapper.selectProTaskWorkunitByTaskWorkunitId(taskWorkunitId);
        ExceptionUtil.checkTrueThrowException(
                (Objects.equals(proTask.getStatus(), TaskStatusEnum.FINISHED.getStatus()) && !Objects.equals(proTaskWorkunit.getStatus(), TaskStatusEnum.BEGINNING.getStatus()))
                        || Objects.equals(proTask.getStatus(), TaskStatusEnum.CLOSE.getStatus()), MessageUtils.message("pro.feedback.error.before.start"));

        ExceptionUtil.checkTrueThrowException(Objects.equals(proTask.getStatus(), proTaskWorkunit.getStatus()) && Objects.equals(proTaskWorkunit.getStatus(), TaskStatusEnum.BEGINNING.getStatus()), "不可重复开工");

        ExceptionUtil.checkTrueThrowException(Objects.equals(proTask.getStatus(), proTaskWorkunit.getStatus()) && Objects.equals(proTaskWorkunit.getStatus(), TaskStatusEnum.PAUSE.getStatus()), "当前订单已经暂停");


        List<ProTask> proTasks = proTaskMapper.selectListJoinByQw(new QueryWrapper<ProTask>().eq("t1.task_id", proTask.getTaskId()));
        ProTask task = proTasks.get(0);


        proTasks = proTaskMapper.selectProTaskVoList(taskWorkunitId, task.getArrangeCode());
        task = proTasks.get(0);




        if (proTask.getStatus().equals(TaskStatusEnum.BEGINNING.getStatus())) {
            proTaskWorkunit.setStatus(proTask.getStatus());
            proTaskWorkunitService.updateProTaskWorkunitState(proTaskWorkunit, TaskStatusEnum.get(proTask.getStatus()));
        }

        if (proTask.getStatus().equals(TaskStatusEnum.FINISHED.getStatus())) {
            ProWorkorder proWorkorder = new ProWorkorder();
            proWorkorder.setTaskId(proTask.getTaskId());
            List<ProWorkorder> proWorkorders = proWorkorderService.selectProWorkorderByTaskId(proWorkorder);

            List<ProStartWork> proStartWorks = proStartWorkService.selectListByTwId(taskWorkunitId);
            proStartWorks.stream().filter(x -> Objects.equals(x.getRecordType(), ProStartWorkEnum.START.getType())).findFirst().ifPresent(
                    x -> {
                        x.setRecordType(ProStartWorkEnum.CLOSE.getType());
                        proStartWorkService.updateProStartWork(x);
                    }
            );


            //最后一道工序完工
            if (proTask.getIsLastProcess() != null && proTask.getIsLastProcess() == 1) {
                //最后一个批次，回写关联订单状态为已完成
                QueryWrapper<ProTaskWorkunit> taskWorkuniQuery = new QueryWrapper<>();
                taskWorkuniQuery.eq("task_id", proTask.getTaskId());
                taskWorkuniQuery.notIn("status", TaskStatusEnum.FINISHED.getStatus());//存在未完工状态数据
                List<ProTaskWorkunit> tempList = proTaskWorkunitService.selectListByQw(taskWorkuniQuery);
                if (CollectionUtil.isEmpty(tempList)) {
                    for (ProWorkorder workorder : proWorkorders) {
                        workorder.setStatus(WorkorderStatusEnum.FINISHED.getValue());
                        proWorkorderService.updateProWorkorder(workorder);
                    }
                }


                //创建入库单
                for (ProWorkorder workorder : proWorkorders) {
                    WmProductRecpt insertProduct = new WmProductRecpt();

                    insertProduct.setWorkorderId(workorder.getWorkorderId());
                    insertProduct.setWorkorderCode(workorder.getWorkorderCode());
                    insertProduct.setWorkorderName(workorder.getWorkorderName());
                    insertProduct.setItemId(task.getItemId());
                    insertProduct.setItemCode(task.getItemCode());
                    insertProduct.setItemName(task.getItemName());
                    insertProduct.setUnitOfMeasure(task.getUnitOfMeasure());
                    insertProduct.setRecptDate(DateUtils.getNowDate());
                    insertProduct.setStatus(TaskStatusEnum.FINISHED.getStatus());
                    insertProduct.setRecptName(workorder.getWorkorderName());
                    int recptId = wmProductRecptService.insertWmProductRecpt(insertProduct);

                    if (recptId > 0) {
                        WmProductRecptLine wmProductRecptLine = new WmProductRecptLine();
                        wmProductRecptLine.setRecptId(insertProduct.getRecptId());
                        wmProductRecptLine.setCreateTime(DateUtils.getNowDate());
                        wmProductRecptLine.setItemId(task.getItemId());
                        wmProductRecptLine.setItemCode(task.getItemCode());
                        wmProductRecptLine.setItemName(task.getItemName());
                        wmProductRecptLine.setSpecification(task.getSpecification());
                        wmProductRecptLine.setUnitOfMeasure(task.getUnitOfMeasure());
                        wmProductRecptLine.setQuantityRecived(workorder.getQuantityProduced());
                        wmProductRecptLine.setBatchCode(workorder.getBatchCode());
                        wmProductRecptLineService.insertWmProductRecptLine(wmProductRecptLine);
                    }

                }
            }
        }

        //新增更新记录
        if (proTask.getStatus().equals(TaskStatusEnum.BEGINNING.getStatus())) {
            proStartWorkService.insertObj(proTask);
        }

        //暂停更新记录
        if (proTask.getStatus().equals(TaskStatusEnum.PAUSE.getStatus())) {
            proTask.setPurseType(ProStartWorkEnum.SUSPENDED.getType());
            proStartWorkService.updateObj(proTask);
        }

        this.updateProTask(proTask);
    }


    @Override
    @Transactional
    public void manualSchedule(ProTaskVo proTaskVo) {
        // 封装保存
        ProTask dbTask = this.selectProTaskByTaskId(proTaskVo.getTaskId());
        Long taskId = dbTask.getTaskId();
        dbTask.setStartTime(proTaskVo.getStartTime());
        dbTask.setDuration(proTaskVo.getDuration());
        Date endTime = proTaskVo.getStartTime();
        dbTask.setStatus(TaskStatusEnum.PREPARE.getStatus());

        this.updateProTask(dbTask);

        // 封装任务-工作单元
        ProTaskWorkunit proTaskWorkunit = new ProTaskWorkunit();
        proTaskWorkunit.setTaskId(taskId);
        proTaskWorkunit.setIdx(1L);
        proTaskWorkunit.setQuantityProduced(BigDecimal.ZERO);
        proTaskWorkunit.setQuantityQualify(BigDecimal.ZERO);
        proTaskWorkunit.setQuantityUnqualify(BigDecimal.ZERO);
        proTaskWorkunit.setStatus(TaskStatusEnum.PREPARE.getStatus());
        proTaskWorkunit.setQuantity(proTaskVo.getQuantity());
        proTaskWorkunit.setWorkunitId(proTaskVo.getWorkunitId());
        proTaskWorkunit.setScheduleStartDate(proTaskVo.getStartTime());
        if (proTaskVo.getEndTime() != null) {
            proTaskWorkunit.setScheduleEndDate(proTaskVo.getEndTime());
        } else {
            proTaskWorkunit.setScheduleEndDate(endTime);
        }
        proTaskWorkunitService.insertProTaskWorkunit(proTaskWorkunit);

        // 自动生产物料领用单
        proTaskVo.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
        iProMaterialRequestService.insertProMaterialRequestItem(proTaskVo);

        //自动生成刀模版申请单
        proTaskVo.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
        proTaskVo.setTaskId(taskId);
        tmToolRequestService.addedToolRequestAppForm(Collections.singletonList(proTaskWorkunit));

        // 更新工单状态
        String arrangeCode = dbTask.getArrangeCode();
        ProWorkorder proWorkorder = new ProWorkorder();
        proWorkorder.setArrangeCode(arrangeCode);
        proWorkorder.setStatus(WorkorderStatusEnum.SCHEDULED.getValue());
        proWorkorder.updateAction();
        proWorkorderService.updateWoStatusByArrangeCode(proWorkorder);
    }

    private void sortDeduction(List<ProTaskWorkunit> proTaskWorkunits, AtomicReference<Double> splitQuantity, String status) {
        List<ProTaskWorkunit> preTaskWorkunits = proTaskWorkunits.stream().filter(x -> Objects.equals(x.getStatus(), status)).collect(Collectors.toList());
        preTaskWorkunits.forEach(x -> {
            BigDecimal quantityProduced = x.getQuantityProduced();

            BigDecimal quantity = x.getQuantity();

            BigDecimal waitSize = quantity.subtract(quantityProduced);
            Double v = splitQuantity.get();
            double waitSizeDouble = waitSize.doubleValue();
            if (waitSizeDouble > 0) {
                if (v > 0) {

//                    10 - 3 = 7   3 - 10 = -7
                    double newValue = v - waitSizeDouble;
                    if (newValue > 0) {
                        splitQuantity.set(newValue);
                        x.setQuantity(quantity.subtract(new BigDecimal(waitSizeDouble)));
                    } else {
                        splitQuantity.set(0D);
                        x.setQuantity(quantity.subtract(new BigDecimal(v)));
                    }
                }

            }

        });

        for (ProTaskWorkunit proTaskWorkunit : proTaskWorkunits) {
            proTaskWorkunit.setApiFlag(true);
            proTaskWorkunitService.updateProTaskWorkunit(proTaskWorkunit);
        }

    }

    @Override
    public ProTaskWorkunit splitTask(ProTaskVo proTaskVo, Integer type) {
        QueryWrapper<ProTaskWorkunit> proTaskWorkunitQueryWrapper = new QueryWrapper<>();
        Long taskId = proTaskVo.getTaskId();
        proTaskWorkunitQueryWrapper.eq("task_id", taskId);
        proTaskWorkunitQueryWrapper.in("task_type", TaskConst.NORMAL_TASK_LIST);
        List<ProTaskWorkunit> proTaskWorkunits = proTaskWorkunitMapper.selectListByQw(proTaskWorkunitQueryWrapper);
        ExceptionUtil.checkTrueThrowException(CollectionUtil.isEmpty(proTaskWorkunits), MessageUtils.message("pro.schedule.error.not.exist.main.task"));

        ProTask proTask = this.selectBaseById(taskId);
        ProTaskWorkunit taskWorkunitSplitConst = proTaskVo.getTaskWorkunit();
        BigDecimal splitQuantityConst = taskWorkunitSplitConst.getQuantity();
        ExceptionUtil.checkTrueThrowException(
                splitQuantityConst.doubleValue() > proTask.getQuantityWait().doubleValue(),
                MessageUtils.message("pro.schedule.error.split.quantity.lack"));


        ProTaskWorkunit mainTaskWorkunitVal = null;
        if (TaskConst.ASSIST_TASK.equals(type)) {
            DoubleSummaryStatistics summaryStatistics = proTaskWorkunits.stream().map(x -> x.getQuantity().subtract(x.getQuantityProduced()).doubleValue()).filter(x -> x > 0).collect(Collectors.summarizingDouble(x -> x));
            double sum = summaryStatistics.getSum();

            AtomicReference<Double> splitQuantity = new AtomicReference<>(splitQuantityConst.doubleValue());

            sortDeduction(proTaskWorkunits, splitQuantity, TaskWorkunitStatusEnum.PREPARE.getStatus());
            sortDeduction(proTaskWorkunits, splitQuantity, TaskWorkunitStatusEnum.BEGINNING.getStatus());
            sortDeduction(proTaskWorkunits, splitQuantity, TaskWorkunitStatusEnum.PAUSE.getStatus());
            sortDeduction(proTaskWorkunits, splitQuantity, TaskWorkunitStatusEnum.ERROR_STOP.getStatus());


        } else {
            mainTaskWorkunitVal = proTaskWorkunits.get(0);
            BigDecimal mainQuantity = mainTaskWorkunitVal.getQuantity();
            BigDecimal subWaitQuantity = mainQuantity.subtract(mainTaskWorkunitVal.getQuantityProduced());

            ExceptionUtil.checkTrueThrowException(
                    subWaitQuantity.doubleValue() < splitQuantityConst.doubleValue(),
                    MessageUtils.message("pro.schedule.error.split.quantity.lack"));

            ExceptionUtil.checkTrueThrowException(
                    splitQuantityConst.doubleValue() > mainQuantity.intValue(), MessageUtils.message("pro.schedule.error.split.quantity.lack"));


            mainTaskWorkunitVal.setQuantity(mainQuantity.subtract(splitQuantityConst));
            if (Objects.equals(type, TaskConst.ASSIST_TASK)) {
                mainTaskWorkunitVal.setApiFlag(true);
            }
            proTaskWorkunitService.updateProTaskWorkunit(mainTaskWorkunitVal);

        }


        ProTaskWorkunit insertTaskWorkunit = proTaskVo.deepSetObj(taskWorkunitSplitConst);
        String workunitName = taskWorkunitSplitConst.getWorkunitName();
        Long workunitId = taskWorkunitSplitConst.getWorkunitId();
        QueryWrapper<MdWorkunit> mdWorkunitQueryWrapper = new QueryWrapper<>();
        mdWorkunitQueryWrapper.eq(StringUtils.isNotEmpty(workunitName), "workunit_name", workunitName);
        mdWorkunitQueryWrapper.eq(StringUtils.isNotEmpty(workunitId), "workunit_id", workunitId);
        List<MdWorkunit> mdWorkunits = mdWorkunitMapper.selectListByQw(mdWorkunitQueryWrapper);

        MdWorkunit mdWorkunit = mdWorkunits.get(0);
        insertTaskWorkunit.setWorkunitId(mdWorkunit.getWorkunitId());
        insertTaskWorkunit.setWorkunitCode(mdWorkunit.getWorkunitCode());
        insertTaskWorkunit.setWorkunitName(mdWorkunit.getWorkunitName());

        // 封装任务-工作单元
        insertTaskWorkunit.setQuantity(splitQuantityConst);
        insertTaskWorkunit.setQuantityProduced(BigDecimal.ZERO);
        insertTaskWorkunit.setQuantityQualify(BigDecimal.ZERO);
        insertTaskWorkunit.setQuantityUnqualify(BigDecimal.ZERO);
        insertTaskWorkunit.setStatus(TaskStatusEnum.PREPARE.getStatus());
        insertTaskWorkunit.setTaskType(type);

        Date startTime = proTaskVo.getScheduleStartDate() == null ? new Date() : proTaskVo.getScheduleStartDate();
        insertTaskWorkunit.setScheduleStartDate(startTime);
        insertTaskWorkunit.setScheduleEndDate(new Date(startTime.getTime() + proTaskVo.getDuration() * 1000 * 60 * 60));
        if (Objects.equals(type, TaskConst.ASSIST_TASK)) {
            insertTaskWorkunit.setApiFlag(true);

        }

        proTaskWorkunitService.insertProTaskWorkunit(insertTaskWorkunit);
        return insertTaskWorkunit;
    }

    @Override
    @Transactional
    public void taskWorkunitSplit(ProTaskVo proTaskVo) {
        ProTaskWorkunit taskWorkunit = splitTask(proTaskVo, TaskConst.SPLIT_TASK);
        proTaskVo.setQuantity(taskWorkunit.getQuantity());
        proTaskVo.setStartTime(DataUtil.repliceData(proTaskVo.getStartTime(), proTaskVo.getScheduleStartDate()));
        proTaskVo.setEndTime(DataUtil.repliceData(proTaskVo.getEndTime(), proTaskVo.getScheduleEndDate()));
        proTaskVo.setTaskWorkunitId(taskWorkunit.getTaskWorkunitId());

        ProTask proTask = proTaskVo.deepCopyObj(ProTask.class);

        // 自动生产物料领用单
        iProMaterialRequestService.insertProMaterialRequestItemV2(proTask);

        // 自动生成刀模版申请单
        tmToolRequestService.copyTmToolMachines(proTask);
    }

    @Override
    @Transactional
    public void copyTask(ProTask proTask) {
        // 封装保存
        this.updateProTask(proTask);

        // 封装任务-工作单元
        ProTaskWorkunit proTaskWorkunit = new ProTaskWorkunit();
        proTaskWorkunit.setTaskId(proTask.getTaskId());
        proTaskWorkunit.setIdx(1L);
        proTaskWorkunit.setWorkunitId(proTask.getWorkunitId());
        proTaskWorkunit.setUnitOfMeasure(proTask.getUnitOfMeasure());
        proTaskWorkunit.setQuantity(proTask.getQuantity());
        proTaskWorkunit.setQuantityProduced(BigDecimal.ZERO);
        proTaskWorkunit.setQuantityQualify(BigDecimal.ZERO);
        proTaskWorkunit.setQuantityUnqualify(BigDecimal.ZERO);
        proTaskWorkunit.setStatus(TaskStatusEnum.PREPARE.getStatus());

        if (proTask.getStartTime() != null) {
            proTaskWorkunit.setScheduleStartDate(proTask.getStartTime());
        }

        if (proTask.getEndTime() != null && proTask.getStartTime() != null) {
            proTaskWorkunit.setScheduleEndDate(proTask.getEndTime() == null ? new Date(proTask.getStartTime().getTime() + proTask.getDuration() * 1000 * 60 * 60) : proTask.getEndTime());
        }

        proTaskWorkunitService.insertProTaskWorkunit(proTaskWorkunit);

        // 自动生产物料领用单
        iProMaterialRequestService.insertProMaterialRequestItemV2(proTask);

        // 自动生成刀模版申请单
        proTask.setTaskWorkunitId(proTaskWorkunit.getTaskWorkunitId());
        proTask.setTaskId(proTask.getTaskId());
        tmToolRequestService.copyTmToolMachines(proTask);
    }

    @Override
    public List<ProTask> selectEquipmentNewestTask(QueryWrapper<ProTask> taskQuery) {
        return proTaskMapper.selectEquipmentNewestTask(taskQuery);
    }

    @Override
    public List<ProTask> selectProTaskByWorkorderCode(String workorderCode) {
        QueryWrapper<ProTask> proTaskQueryWrapper = new QueryWrapper<>();
        proTaskQueryWrapper.eq("workorder_code", workorderCode);
        return proTaskMapper.selectListJoinByQw(proTaskQueryWrapper);
    }

    @Override
    public void closeObj(List<ProTaskVo> taskVos) {
        if (CollectionUtil.isNotEmpty(taskVos)) {
            for (ProTaskVo taskVo : taskVos) {
                ProTask proTask = taskVo.deepCopyObj(ProTask.class);
                if (proTask.getQuantity().doubleValue() == 0) {
                    proTask.setStatus(TaskStatusEnum.CLOSE.getStatus());
                }
                proTaskMapper.updateProTask(proTask);
            }
        }

    }


    @Override
    public ProTask getNextTaskByTaskId(Long taskId) {
        ProTask thisProTask = this.selectProTaskByTaskId(taskId);
        QueryWrapper<ProTask> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("task_batch", thisProTask.getTaskBatch());
        queryWrapper.notIn(StringUtils.isNotEmpty(taskId), "task_id", taskId);
        queryWrapper.ge(StringUtils.isNotEmpty(thisProTask.getOrdinal()), "ordinal", thisProTask.getOrdinal());
        queryWrapper.orderByAsc("ordinal");
        List<ProTask> tasks = proTaskMapper.selectListByQw(queryWrapper);
        if(tasks.size()==0){
            return null;
        }
        return tasks.get(0);
    }

    @Override
    public List<ProTask> selectListByQw(QueryWrapper<ProTask> proTaskQueryWrapper) {
        return proTaskMapper.selectListJoinByQw(proTaskQueryWrapper);
    }

    @Transactional
    @Override
    public void schedule(List<WorkorderScheduleParams> workorderScheduleParams) {
        BaoshenScheduleAlgorithmAdapter baoshenScheduleAlgorithmAdapter = new BaoshenScheduleAlgorithmAdapter();
        baoshenScheduleAlgorithmAdapter.setAlgorithmDataSource(algorithmDataSource);
        baoshenScheduleAlgorithmAdapter.setAlgorithmResultProcess(algorithmResultProcess);
        EquipmentSelectionStrategyImpl defaultStrategy = new EquipmentSelectionStrategyImpl();
        baoshenScheduleAlgorithmAdapter.setEquipmentSelectionStrategy(defaultStrategy);
        baoshenScheduleAlgorithmAdapter.setAlgorithmExtendDataSources(new ArrayList<AlgorithmExtendDataSource>() {
            private static final long serialVersionUID = -4466020352312471396L;
            {
                add(equipmentNewestTaskAlgorithmData);
                add(scheduleSetupRuleAlgorithmData);
            }
        });
        baoshenScheduleAlgorithmAdapter.schedule(LocalDateTime.now(),
                workorderScheduleParams);

        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        stopWatch.stop();
        logger.info(String.format("排产结果发送SAP耗时：%s", stopWatch.getTotalTimeSeconds()));

    }

    @Override
    public ProTask selectBaseById(Long taskId) {
        List<ProTask> proTasks = proTaskMapper.selectListByQw(new QueryWrapper<ProTask>().eq("task_id", taskId));

        return proTasks.get(0);
    }


    @Override
    @Transactional
    public List<ProTask> getTaskList(ProTaskQuery proTask) {
        ProTaskQuery proTaskQuery = new ProTaskQuery();
        BeanUtils.copyProperties(proTask, proTaskQuery);
        //判断前端传来是编号还是工单
        if (StringUtils.isNotEmpty(proTask.getArrangeCode())) {
            if (proTask.getArrangeCode().length() == 12) {
                proTask.setWorkorderCode(proTask.getArrangeCode());
                proTask.setArrangeCode(null);
            }
        }

        List<ProTask> rst = new ArrayList<>();
        List<ProTask> list = new ArrayList<>();
        QueryWrapper<ProTask> query = new QueryWrapper<>();
        List<String> statusList = Arrays.asList(TaskStatusEnum.BEGINNING.getStatus(), TaskStatusEnum.PREPARE.getStatus(),
                TaskStatusEnum.PAUSE.getStatus(), TaskStatusEnum.ERROR_STOP.getStatus());
        query.in("ptw.status", statusList);
        query.eq(proTask.getWorkunitId() != null, "mw.workunit_id", proTask.getWorkunitId());
        query.eq(proTask.getOutsourced() != null, "ptw.outsourced", proTask.getOutsourced());
        query.eq(StringUtils.isNotEmpty(proTask.getArrangeCode()), "t.arrange_code", proTask.getArrangeCode());
        query.gt(proTask.getAllowProduce() != null && proTask.getAllowProduce() == 1, "t.quantity_wait", 0);
        query.gt("ptw.quantity", 0);
        query.orderByAsc("statusIndex").orderByAsc("ptw.schedule_start_date");
        //搜索条件为工单号查询相应任务ID作为查询条件
        if (StringUtils.isNotEmpty(proTask.getWorkorderCode())) {
            QueryWrapper<ProTask> taskQuery = new QueryWrapper<>();
            taskQuery.eq("t2.workorder_code", proTask.getWorkorderCode());
            taskQuery.eq(proTask.getWorkunitId() != null, "t4.workunit_id", proTask.getWorkunitId());
            List<ProTaskVo> taskVoList = proTaskMapper.selectProTaskJoinWorkorder(taskQuery);
            if (CollectionUtil.isEmpty(taskVoList)) {
                if (CollectionUtil.isNotEmpty(rst)) {
                    for (ProTask task : rst) {
                        Double v = proFeedbackService.selectQuantityQualifySum(new ProFeedback(task.getArrangeCode(), null, null, task.getTaskWorkunitId()));
                        task.setArrangeFeedbackSum(v);
                    }
                }
                return rst;
            } else {
                query.in("t.task_id", taskVoList.stream().map(ProTaskVo::getTaskId).collect(Collectors.toList()));
            }
        }
        list = this.selectProTaskJoinTaskWorkUnit(query);

        rst = list.stream().filter(t -> !TaskStatusEnum.FINISHED.getStatus().equals(t.getStatus())).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(rst)) {
            for (ProTask task : rst) {
                String arrangeCode = task.getArrangeCode();
                if (StringUtils.isNotEmpty(arrangeCode)) {
                    ProWorkorderQuery workorderQuery = new ProWorkorderQuery();
                    workorderQuery.setWorkorderCode(arrangeCode);
                    List<ProWorkorder> proWorkorders = proWorkorderService.selectProWorkorderList(workorderQuery);
                    task.setProWorkorderList(proWorkorders);
                    if(proWorkorders.size() > 0 && proWorkorders.get(0).getProductionSolutionId() != null){
                        ProProductionSolution proProductionSolution
                                = proProductionSolutionMapper.selectProProductionSolutionByProductionSolutionId(proWorkorders.get(0).getProductionSolutionId());
                        if(proProductionSolution != null){
                            task.setSurpassState(proProductionSolution.getSurpassState());
                        }
                    }
                    Double v = proFeedbackService.selectQuantityQualifySum(new ProFeedback(arrangeCode, null, null, task.getTaskWorkunitId()));
                    task.setArrangeFeedbackSum(v);
                }
            }
        }

        Set<Long> taskWorkunitIds = rst.stream().map(ProTask::getTaskWorkunitId).collect(Collectors.toSet());
        if (CollectionUtil.isNotEmpty(taskWorkunitIds)) {
            Map<Long, ProTaskAssistProcess> assistProcessMap = proTaskAssistProcessMapper.selectListByQw(new QueryWrapper<ProTaskAssistProcess>().in("task_workunit_id", taskWorkunitIds)).stream().collect(Collectors.toMap(ProTaskAssistProcess::getTaskWorkunitId, x -> x));

            List<ProTask> proTasks = proTaskWorkunitMapper.selectListIsExistToolByTaskWorkunitIds(new QueryWrapper<ProTaskWorkunit>().in("task_workunit_id", taskWorkunitIds));
            Map<Long, ProTask> isExistToolList = proTasks.stream().collect(Collectors.toMap(ProTask::getTaskWorkunitId, x -> x));

            for (ProTask task : rst) {
                ProTaskAssistProcess assistProcess = assistProcessMap.get(task.getTaskWorkunitId());
                ProTask taskVal = isExistToolList.get(task.getTaskWorkunitId());

                if (taskVal != null) {
                    task.setIsExistTool(taskVal.getIsExistTool());
                }

                if (assistProcess != null) {
                    task.setCloseType(assistProcess.getCloseType());
                    task.setWorkorderCode(assistProcess.getWorkorderCode());
                }
            }


        }
        return rst;

    }

    @Override
    public List<ProTaskLinkFile> getTaskLinkFile(ProTaskQuery proTask) {

        return null;
    }
}
