package com.shkj.wms.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ser.impl.FailingSerializer;
import com.google.common.collect.Sets;
import com.shkj.common.annotation.Log;
import com.shkj.common.constant.RedisConstant;
import com.shkj.common.core.domain.Result;
import com.shkj.common.enums.HttpStatus;
import com.shkj.common.utils.DateUtils;
import com.shkj.common.utils.SecurityUtils;
import com.shkj.common.utils.StringUtils;
import com.shkj.framework.config.SecurityConfig;
import com.shkj.system.service.ISysParameterService;

import com.shkj.wms.bo.*;
import com.shkj.wms.constants.ParameterConstants;
import com.shkj.wms.domain.*;
import com.shkj.wms.enums.TaskStatusEnum;
import com.shkj.wms.enums.TaskTypeEnum;
import com.shkj.wms.mapper.*;
import com.shkj.wms.service.*;
import com.shkj.wms.third.rcs.RCSUtil;
import com.shkj.wms.third.rcs.dto.RcsCreateTaskDto;
import com.shkj.wms.third.rcs.dto.RcsIdList;
import com.shkj.wms.third.rcs.enums.RCSTaskTypeEnum;
import com.shkj.wms.utils.JsonUtil;
import com.shkj.wms.utils.TunnelTaskUtil;
import com.shkj.wms.vo.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.math3.linear.ConjugateGradient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 任务管理Service业务层处理
 *
 * @author zjx
 * @date 2023-04-07
 */
@Slf4j
@Service
public class BusinDataTaskServiceImpl extends ServiceImpl<BusinDataTaskMapper, BusinDataTask> implements IBusinDataTaskService {
    @Resource
    private BusinDataTaskMapper businDataTaskMapper;

    @Resource
    private BusinDataTaskDetailMapper businDataTaskDetailMapper;

    @Resource
    RedisTemplate redisTemplate;

    @Resource
    BaseLocationPlcMapper baseLocationPlcMapper;

    @Autowired
    private IBaseStorageService iBaseStorageService;

    @Resource
    ISysParameterService sysParameterService;

    @Resource
    BaseLocationServiceImpl baseLocationService;

    @Resource
    IBaseDeriveService iBaseDeriveService;

    @Resource
    IBaseGoodsDataService iBaseGoodsDataService;

    @Resource
    IBaseBarcodesOutService iBaseBarcodesOutService;

    @Resource
    IBaseBarcodesInService iBaseBarcodesInService;

    @Resource
    IBusinDataTaskGoodsService iBusinDataTaskGoodsService;

    @Resource
    IBusinDataTaskService iBusinDataTaskService;

    @Resource
    IPutInOutStorageService iPutInOutStorageService;

    @Resource
    BaseGoodsDataMapper baseGoodsDataMapper;

    @Resource
    SysStockDetailMapper sysStockDetailMapper;

    @Resource
    private TunnelTaskUtil tunnelTaskUtil;

    @Autowired
    ISysParameterService isysParameterService;

    @Resource
    IBusinEnptyContainerService iBusinEnptyContainerService;


    @Autowired
    ISysStockDetailService iSysStockDetailService;

    @Resource
    BasePointDeviceMapper basePointDeviceMapper;

    @Resource
    RCSUtil rcsUtil;
    @Resource
    BaseLocationMapper baseLocationMapper;
    @Autowired
    private IBasePointService iBasePointService;

    @Autowired
    private IBaseContainerService iBaseContainerService;
    @Resource
    IBaseLocationService iBaseLocationService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> insertBusinTask(BaseContainerCallBo callBo) {
        String pointType = callBo.getPointType();
        String toPoint = callBo.getPointNo();

        if (StringUtils.isNull(toPoint) || StringUtils.isEmpty(toPoint)) {
            if (pointType.equals("out")) {
                //获取出库异常区接驳点


                String tepairGroup = sysParameterService.selectConfigByKey(SecurityUtils.getCurrentBranchId(), ParameterConstants.ParameterSystem.putoutexc_point);
                BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
                pointQueryBo.setGroupNo(tepairGroup);
                BasePointDeviceVo pointDevice = basePointDeviceMapper.selectBasePointByGroupno(pointQueryBo);
                toPoint = pointDevice.getPointNo();
            }
        }

        if (StringUtils.isEmpty(toPoint)) {
            return Result.err().msg("维护出库异常接驳点位");
        }

        //验证点位信息已经呼叫，尚未执行给与提示信息
        BasePointDeviceQueryBo bo = new BasePointDeviceQueryBo();
        bo.setPointNo(callBo.getPointNo());
        BasePointDeviceVo basePointDeviceVo = baseLocationPlcMapper.selectBasePointByGroupno(bo).get(0);
        if (basePointDeviceVo == null) {
            return Result.err().msg("点位信息不存在");
        }

        String taskCode = "T" + DateUtils.dateTime();
        BusinTaskAddBo businTaskAddBo = new BusinTaskAddBo();
        businTaskAddBo.setTaskType(TaskTypeEnum.call_container.getValue());
        businTaskAddBo.setTaskCode(taskCode);
        businTaskAddBo.setTaskStatus(TaskStatusEnum.wait_put.getValue());
        businTaskAddBo.setIsDown(basePointDeviceVo.getIsDown());
        businTaskAddBo.setTaskPath(toPoint);

        BusinTaskDetailAddBo dtls = new BusinTaskDetailAddBo();
        dtls.setTaskCode(taskCode);
        dtls.setEndLocation(toPoint);
        dtls.setUpdateTime(DateUtils.getNowDate());

        BusinDataTask businDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);
        this.baseMapper.insertBusinDataTask(businDataTask);
        String taskid = String.valueOf(businDataTask.getId());
        Map map = new HashMap();
        map.put("taskid", taskid);

        businDataTaskDetailMapper.insert(BeanUtil.toBean(dtls, BusinDataTaskDetail.class));
        return Result.ok().data(map);
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> insertBusinTask(BusinDataTask businDataTask) {
        int randomoperands = (int) Math.round(Math.random() * 1000);
        String taskCode = "T_" + DateUtils.dateTimeNow() + randomoperands;
        if (businDataTask.getTaskType().isEmpty()) {
            businDataTask.setTaskType(TaskTypeEnum.call_container.getValue());
        }
        businDataTask.setTaskCode(taskCode);
        if (businDataTask.getTaskStatus().isEmpty()) {
            businDataTask.setTaskStatus(TaskStatusEnum.wait_put.getValue());
        }
        this.save(businDataTask);
        return Result.ok();
    }

    @Override
    public Result<Boolean> insertBusinTask(List<BaseBarcodesOutAddBo> bs) {
        log.info("出库任务信息：" + JsonUtil.toJSONString(bs));

        List<BusinDataTask> taskList = new ArrayList<>();

        int proportionP01 = 0;
        int proportionP02 = 0;

        int tempP01 = 0;
        int tempP02 = 0;

        boolean numberAdd = false;
        boolean proportionStatus = true;

        if (ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.out_plan_type)) && redisTemplate.opsForValue().get(RedisConstant.out_plan_type).toString().contains("比例")) {
            numberAdd = true;
            //查询获取每个货区的比例
            BaseStorageQueryListBo baseStorageQueryListBo = new BaseStorageQueryListBo();
            Map dataScopeBranchmap = new HashMap();
            dataScopeBranchmap.put("dataScopeBranch", 2);
            baseStorageQueryListBo.setBranchParams(dataScopeBranchmap);
            List<BaseStorageVo> baseStorageVos = iBaseStorageService.queryBaseStorageListA(baseStorageQueryListBo);

            for (BaseStorageVo baseStorageVo : baseStorageVos) {
                if ("P01".equals(baseStorageVo.getStorageCode())) {
                    proportionP01 = Integer.parseInt(baseStorageVo.getExtend1());
                } else if ("P02".equals(baseStorageVo.getStorageCode())) {
                    proportionP02 = Integer.parseInt(baseStorageVo.getExtend1());
                }
            }


            if (ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get("task_P01_number"))) {
                tempP01 = Integer.parseInt(redisTemplate.opsForValue().get("task_P01_number").toString());
                tempP02 = Integer.parseInt(redisTemplate.opsForValue().get("task_P02_number").toString());
                if (tempP01 == proportionP01) {
                    if (tempP02 == proportionP02) {
                        redisTemplate.opsForValue().set("task_P01_number", 0);
                        redisTemplate.opsForValue().set("task_P02_number", 0);
                        proportionStatus = true;
                    } else {
                        proportionStatus = false;
                    }
                }
            } else {
                redisTemplate.opsForValue().set("task_P01_number", 0);
            }
        } else {
            if (ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.out_plan_type)) && redisTemplate.opsForValue().get(RedisConstant.out_plan_type).toString().contains("立库")) {
                proportionStatus = true;
            } else if (ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.out_plan_type)) && redisTemplate.opsForValue().get(RedisConstant.out_plan_type).toString().contains("平库")) {
                proportionStatus = false;
            }
        }

        for (int i = 0; i < bs.size(); i++) {
            List<BusinDataTaskGoods> taskGoodsList = new ArrayList<>();
            BaseBarcodesOutAddBo baseBarcodesOut = bs.get(i);
            //回填出库队列的状态
            baseBarcodesOut.setOutStatus("1");
            //根据出库中的车型代码，派生查找派生表中的保险杠信息
            BaseDeriveQueryBo baseDeriveQueryBo = new BaseDeriveQueryBo();
            baseDeriveQueryBo.setDerive(baseBarcodesOut.getDerive());
            baseDeriveQueryBo.setVehicheCode(baseBarcodesOut.getVehicleCode());
            baseDeriveQueryBo.setColor(baseBarcodesOut.getColor());

            BaseDerive baseDerive = iBaseDeriveService.getBaseDeriveBybarcodes(baseDeriveQueryBo);
            if (ObjectUtils.isNotEmpty(baseDerive)) {

                //获取出库组装接驳点位
                String pointout = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.Manual_drop_point);
                BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();

                pointQueryBo.setGroupNo(pointout);
                List<BasePointDeviceVo> pointDeviceout = basePointDeviceMapper.getBasePointByGroupNoList(pointQueryBo);
                List<String> dbTableColumnNames = pointDeviceout.stream().map(BasePointDeviceVo::getPointNo).collect(Collectors.toList());
                String urgencyBefore = null;
                String urgencyAfter = null;
                for (String str : dbTableColumnNames
                ) {
                    // TODO 中科  测试 需要还原
                    if (str.equals(ParameterConstants.ParameterSystem.assemble_point_after)) {
                        urgencyAfter = str;
                    }

                    if (str.equals(ParameterConstants.ParameterSystem.assemble_point_before)) {
                        urgencyBefore = str;
                    }
                    // TODO 中科  测试 需要还原
                    // TODO 中科  测试 需要删除
//                    if (str.equals(ParameterConstants.ParameterSystem.assemble_point_before)) {
//                        urgencyBefore = str;
//                        urgencyAfter = str;
//                    }
                    // TODO 中科  测试 需要删除
                }

                int assemblePointTypeBefore =
                        ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.assemblePointBeforeTaskCount))
                                ? Integer.parseInt(redisTemplate.opsForValue().get(RedisConstant.assemblePointBeforeTaskCount).toString()) : 0;

                int assemblePointTypeAfter =
                        ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.assemblePointAfterTaskCount))
                                ? Integer.parseInt(redisTemplate.opsForValue().get(RedisConstant.assemblePointAfterTaskCount).toString()) : 0;

                //生成作业任务
                BusinDataTask task = new BusinDataTask();
                int randomoperands = (int) Math.round(Math.random() * 1000);
                String taskCode = "T_" + DateUtils.dateTimeNow() + randomoperands;
                task.setTaskCode(taskCode);
                task.setTaskType(TaskTypeEnum.normal_out.getValue());
                if (baseBarcodesOut.getTraverseDate() != null) {
                    task.setBatch(DateUtils.dateTime(baseBarcodesOut.getTraverseDate()));
                }
                task.setPriority("2");
                task.setIsTop("0");
                task.setIsUrgent(baseBarcodesOut.getIsUrgent());
                task.setCreateTime(DateUtils.getNowDate());
                task.setTraverseDate(DateUtils.parseDate(baseBarcodesOut.getTraverseDate()));
                task.setTaskPath(urgencyBefore);
                task.setTaskStatus("0");
                // TODO 测试注释   要打开
//                task.setDistinction("2");
                if (proportionStatus) {
                    task.setDistinction("1");
                } else {
                    task.setDistinction("2");
                }
                taskList.add(task);

                iBaseBarcodesOutService.saveOrUpdate(baseBarcodesOut);

                businDataTaskMapper.insertBusinDataTask(task);
                Long taskId = task.getId();

                if (proportionStatus && numberAdd) {
                    int temp = Integer.parseInt(redisTemplate.opsForValue().get("task_P01_number").toString());
                    redisTemplate.opsForValue().set("task_P01_number", ++temp);
                } else if (!proportionStatus && numberAdd) {
                    int temp = Integer.parseInt(redisTemplate.opsForValue().get("task_P02_number").toString());
                    redisTemplate.opsForValue().set("task_P02_number", ++temp);
                }

                //查询前杠的产品
                List<BaseGoodsData> goodsDataList = iBaseGoodsDataService.getBaseGoodDataInByDerice(baseDerive);
                log.info("查询到的前杠产品：" + JsonUtil.toJSONString(goodsDataList));
                //查询后杠的产品
                List<BaseGoodsData> goodsDatarearList = iBaseGoodsDataService.getBaseGoodDatarear(baseDerive);
                log.info("查询到的后杠产品：" + JsonUtil.toJSONString(goodsDatarearList));
                goodsDataList.addAll(goodsDatarearList);
                for (BaseGoodsData baseGoodsData : goodsDataList) {
                    //根据派生信息查找物料信息，需要前杠和后杠
                    BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                    taskGoods.setGoodsNo(baseGoodsData.getGoodsNo());
                    taskGoods.setTaskCode(taskId);
                    taskGoods.setTraverseDate(baseBarcodesOut.getTraverseDate());
                    //生成作业任务(不分体的后杠分成两个任务)
                    if (baseGoodsData.getLocationCode().equals("H") || baseGoodsData.getLocationCode().equals("R")) {
                        if (baseGoodsData.getIsSplit().equals("0")) {
                            BusinDataTask businDataTask = new BusinDataTask();
                            int randomoperands1 = (int) Math.round(Math.random() * 1000);
                            String busintaskCode = "T_" + DateUtils.dateTimeNow() + randomoperands1;
                            businDataTask.setTaskCode(busintaskCode);
                            businDataTask.setTaskType(TaskTypeEnum.normal_out.getValue());
                            if (baseBarcodesOut.getTraverseDate() != null) {
                                businDataTask.setBatch(DateUtils.dateTime(baseBarcodesOut.getTraverseDate()));
                            }
                            businDataTask.setPriority("2");
                            businDataTask.setIsTop("0");
                            businDataTask.setIsUrgent(baseBarcodesOut.getIsUrgent());
                            businDataTask.setCreateTime(DateUtils.getNowDate());
                            businDataTask.setTraverseDate(DateUtils.parseDate(baseBarcodesOut.getTraverseDate()));
                            businDataTask.setTaskPath(urgencyAfter);
                            // TODO 测试注释   要打开
//                            task.setDistinction("1");
                            if (proportionStatus) {
                                businDataTask.setDistinction("1");
                            } else {
                                businDataTask.setDistinction("2");
                            }
                            businDataTask.setTaskStatus("0");
                            businDataTaskMapper.insertBusinDataTask(businDataTask);
                            taskGoods.setTaskCode(businDataTask.getId());
                        } else {
                            BusinDataTask taskTemp = businDataTaskMapper.selectById(taskId);
                            if (assemblePointTypeBefore > assemblePointTypeAfter) {
                                taskTemp.setTaskPath(urgencyAfter);
                            } else if (assemblePointTypeBefore < assemblePointTypeAfter) {
                                taskTemp.setTaskPath(urgencyBefore);
                            } else if (assemblePointTypeBefore == assemblePointTypeAfter) {
                                taskTemp.setTaskPath(urgencyBefore);
                            }
                            businDataTaskMapper.updateById(taskTemp);
                        }
                    }
                    taskGoodsList.add(taskGoods);
                }
                iBaseBarcodesOutService.updateById(baseBarcodesOut);
            }
            log.info("出库产品明细：" + JsonUtil.toJSONString(taskGoodsList));
            iBusinDataTaskGoodsService.saveBatch(taskGoodsList);
        }

        return Result.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> insertBusinTaskByDervie(List<BaseGoodsDervieBo> bos) {

        List<String> goods = new ArrayList<>();
        //判断保险杠是否是一套，如果选择的保险杠有分体，就默认是一套保险杠，下一个出库任务
        boolean isSuite = false;
        for (BaseGoodsDervieBo bo : bos) {
            String isSplit = bo.getIsSplit();
            if (isSplit.equals("1")) {
                isSuite = true;
            }
        }
        //TODO 判断出库的保险杠是否有库存

        List<BusinDataTask> taskList = new ArrayList<>();
        List<BusinDataTaskGoods> taskGoodsList = new ArrayList<>();
        //获取出库组装接驳点位
        String urgency = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.urgent_out_point);

        if (StringUtils.isEmpty(urgency)) {
            return Result.err().msg("未设定紧急出库接驳点");
        }

        //一套保险杠
        if (isSuite) {
            int index = 0;
            Long taskId = 0L;
            for (BaseGoodsDervieBo bo : bos) {
                if (index == 0) {
                    //生成作业任务
                    BusinDataTask task = new BusinDataTask();
                    String taskCode = "T" + DateUtils.dateTimeNow();
                    task.setTaskCode(taskCode);
                    task.setTaskType(TaskTypeEnum.urgent_out.getValue());
                    task.setPriority("2");
                    task.setIsTop("1");
                    task.setTaskStatus(TaskStatusEnum.wait_put.getValue());
                    task.setIsUrgent(bo.getIsUrgent());
                    task.setCreateTime(DateUtils.getNowDate());
                    task.setTaskPath(urgency);
                    task.setDistinction("1");
                    taskList.add(task);
                    businDataTaskMapper.insertBusinDataTask(task);
                    taskId = task.getId();
                    index++;
                }
                //保险杠信息
                BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                taskGoods.setGoodsNo(bo.getGoodsNo());
                taskGoods.setTaskCode(taskId);
                taskGoods.setIsPunching(bo.getIsPunching());
                taskGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                taskGoodsList.add(taskGoods);
            }
        } else {
            //非分体保险杠，如果出多个时，下多个出库任务
            for (BaseGoodsDervieBo bo : bos) {
                //生成作业任务
                BusinDataTask task = new BusinDataTask();
                String taskCode = "T" + DateUtils.dateTimeNow();
                task.setTaskCode(taskCode);
                task.setTaskType(TaskTypeEnum.urgent_out.getValue());
                task.setPriority("2");
                task.setIsTop("1");
                task.setTaskStatus(TaskStatusEnum.wait_put.getValue());
                task.setIsUrgent(bo.getIsUrgent());
                task.setCreateTime(DateUtils.getNowDate());
                task.setTaskPath(urgency);
                task.setNewDestination("1");
                task.setDistinction("1");
                taskList.add(task);
                businDataTaskMapper.insertBusinDataTask(task);
                Long taskId = task.getId();

                //保险杠信息
                BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                taskGoods.setGoodsNo(bo.getGoodsNo());
                taskGoods.setTaskCode(taskId);
                taskGoods.setIsPunching(bo.getIsPunching());
                taskGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                taskGoodsList.add(taskGoods);
            }
        }

        return iBusinDataTaskGoodsService.saveBatch(taskGoodsList) ? Result.ok() : Result.err().msg("紧急出库确认失败");
    }

    /**
     * 指定货位出库
     *
     * @param locationCode
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> insertBusinTask(String locationCode) {
        /**
         * 1.查询当前货位是不是有库存
         * 2、查询当前货位是不是双深位，如果是，则查询单深位是否有货，如果有货，则提示不可出库
         * 3.生成相关任务，预占出库库存
         * 4.
         */

        try {
            BaseLocationVo baseLocationVo = iBaseLocationService.queryLocationByCode(locationCode);
            if (baseLocationVo == null) {
                return Result.err().msg("未查询到货位信息，请确认！" + locationCode);
            }
            if (baseLocationVo.getLocationStatus().equals("4") || baseLocationVo.getLocationStatus().equals("0")) {
                return Result.err().msg("此货位出库中或已出库，请确认！" + locationCode + " 库位状态：" + baseLocationVo.getLocationStatus());
            }
            List<SysStockDetailVo> sysStockDetailVoList = null;
            //检查货位是否是双深位
            Result<Boolean> booleanResult = checkIsSleep(baseLocationVo);
            if (!Result.isOk(booleanResult)) {
                return booleanResult;
            }
            //确认出库的货位是否有库存信息
            Result<List<SysStockDetailVo>> stockListResult = iSysStockDetailService.queryByLocation(baseLocationVo.getId());
            if (Result.isOk(stockListResult)) {
                sysStockDetailVoList = stockListResult.getData();
                if (sysStockDetailVoList == null && sysStockDetailVoList.size() == 0) {
                    return Result.err().msg("此货位未查询到保险杠信息，请确认！" + locationCode);
                }
            }


            //需要搬运到的码头信息
            String toPoint = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.abnormal_out_point);
            String[] toPoints = toPoint.split("、");

            List<BasePoint> pointList = iBasePointService.list(new LambdaQueryWrapper<BasePoint>()
                    .in(BasePoint::getPointNo, toPoints)
                    .eq(BasePoint::getIsOccupy, "0")
                    .eq(BasePoint::getIsActive, "1")
            );
            String taskPath = "";
            if (pointList != null && pointList.size() == 0) {
                return Result.err().msg("搬运码头无空闲，不可出库");
            }

            BasePoint basePoint = pointList.get(0);
            taskPath = basePoint.getPointNo();
            //预占码头信息
            basePoint.setIsOccupy("1");
            iBasePointService.updateBasePoint(basePoint);
            //预占库存
            baseLocationVo.setLocationStatus("4");
            BaseLocation baseLocation = BeanUtil.toBean(baseLocationVo, BaseLocation.class);
            iBaseLocationService.updateById(baseLocation);
            //生成作业任务
            int index = 0;
            List<BusinDataTaskGoods> taskGoodsList = new ArrayList<>();
            List<SysStockDetail> sysStockDetails = new ArrayList<>();
            Long taskId = 0L;
            for (SysStockDetailVo sysStockDetailVo : sysStockDetailVoList) {
                if (index == 0) {
                    BusinDataTask task = new BusinDataTask();
                    task.setTaskType(TaskTypeEnum.named_loc.getValue());
                    task.setPriority("2");
                    task.setIsTop("0");
                    task.setBatch(sysStockDetailVo.getBatch());
                    task.setTaskStatus(TaskStatusEnum.wait_put.getValue());
                    task.setIsUrgent("0");
                    task.setCreateTime(DateUtils.getNowDate());
                    task.setTaskPath(taskPath);
                    task.setDistinction("1");
                    task.setContainerId(sysStockDetailVo.getContainerCode());
                    task.setFromRow(baseLocationVo.getLocationRow());
                    task.setFromLayer(baseLocationVo.getLayer());
                    task.setFromColumn(baseLocationVo.getLocationColumn());
                    task.setTunnel(baseLocationVo.getTunnel());
                    task.setLocationId(baseLocationVo.getId());
                    this.save(task);
                    taskId = task.getId();
                    index++;
                }

                //保险杠信息
                BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                taskGoods.setGoodsNo(sysStockDetailVo.getGoodsNo());
                taskGoods.setQrCode(sysStockDetailVo.getQrCode());
                taskGoods.setTaskCode(taskId);
                taskGoods.setIsPunching(sysStockDetailVo.getIsPuch());
                taskGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                taskGoods.setCreateBy(SecurityUtils.getUsername());
                taskGoodsList.add(taskGoods);

                //出库预占
                sysStockDetailVo.setOutQty(sysStockDetailVo.getQty().intValue());
                SysStockDetail sysStockDetail = BeanUtil.toBean(sysStockDetailVo, SysStockDetail.class);
                sysStockDetail.setOutTime(DateUtils.getNowDate());
                sysStockDetails.add(sysStockDetail);
            }
            iSysStockDetailService.updateBatchById(sysStockDetails);
            return iBusinDataTaskGoodsService.saveBatch(taskGoodsList) ? Result.ok() : Result.err().msg("指定货位出库失败");
        } catch (Exception e) {
            log.error("指定货位出库失败:" + e.getMessage());
            return Result.err().msg("指定货位出库失败");
        }
    }

    @Override
    public Result<BasePointDeviceVo> getManualWarehousingPoint() {
        BasePointDeviceQueryBo bo = new BasePointDeviceQueryBo();
        //获取人工入库点位分组
        String tepairPoint = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.warehousing_group);

        bo.setGroupNo("10");
        List<BasePointDeviceVo> basePointDeviceVos = baseLocationPlcMapper.selectBasePointByGroupno(bo);
        return Result.ok().data(basePointDeviceVos);
    }

    @Override
    public Result<Boolean> insertBusinTask(BaseBarcodesIn baseBarcodesIn, String taskCode) {
        BusinTaskAddBo businTaskAddBo = new BusinTaskAddBo();
        businTaskAddBo.setTaskCode(taskCode);
        businTaskAddBo.setQrCode(baseBarcodesIn.getQrCode());
        businTaskAddBo.setGoodsNo(baseBarcodesIn.getGoodsNo());
        businTaskAddBo.setTaskStatus("0");
        businTaskAddBo.setBatch(DateUtils.dateTime());
        businTaskAddBo.setIsUrgent("0");
        businTaskAddBo.setIsTop("0");
        businTaskAddBo.setPriority(999);
        businTaskAddBo.setTaskStarttime(new Date());

        this.insertByAddBo(businTaskAddBo);

        return Result.ok();
    }


    @Override
    public Result<Boolean> insertByAddBo(BusinTaskAddBo bo) {
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>().eq(BusinDataTask::getTransId, bo.getTransId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (businDataTask != null) {
            return Result.err().msg("条码信息任务已创建");
        }
        BusinDataTask businDataTaskAdd = BeanUtil.toBean(bo, BusinDataTask.class);
        this.save(businDataTaskAdd);
        return Result.ok();
    }


    @Override
    public Result<Boolean> getReplenishmentAndOutbound(BusinOutboundQueryBo bo) {
        try {
            List<BasinBarcodeInAddBo> barcodesList = bo.getBarcodesList();
            for (BasinBarcodeInAddBo barcode : barcodesList) {
                //根据车型和颜色查询出整套保险杠 A B ，目前知道是A，需要查询B在库存的情况
                //获取车型+颜色
                BaseBarcodesInQueryBo queryBo = new BaseBarcodesInQueryBo();
                queryBo.setVehicheModel(barcode.getVehicheModel());
                queryBo.setColor(barcode.getColor());
                //前后保险杠 0-前 1-后
                queryBo.setLocationCode(barcode.getLocationCode().equals("1") ? "0" : "1");
                // 如果补货的是后杠就差前杠。如果补货的是前杠则相反
                List<BaseGoodsData> goodsDataList = baseGoodsDataMapper.getBaseGoodDataNotBarcode(queryBo);

                queryBo.setIsSplit(barcode.getIsSplit());
                queryBo.setIsPunching(barcode.getIsPunching());
                queryBo.setLocation(barcode.getLocation());
                queryBo.setOrientation(barcode.getOrientation());
                queryBo.setLocationCode(barcode.getLocationCode());
                //查询补货的具体goodsNo
                List<BaseGoodsData> goodsDataList1 = baseGoodsDataMapper.getBaseGoodDataNotBarcode(queryBo);

                List<String> goodsNoList = goodsDataList.stream().map(e -> e.getGoodsNo()).collect(Collectors.toList());

                if (ObjectUtils.isNotEmpty(goodsDataList)) {
                    //查询库存在库情况
                    Map<String, String> detailVos = sysStockDetailMapper.getInventoryInStockByGoods(goodsNoList, barcode.getLocationCode().equals("1") ? goodsDataList1.get(0).getGoodsNo() : null);
                    //生成待执行任务
                    this.insertBusinDataTask(detailVos, bo.getStartPoint());
                }
            }
            return Result.ok();
        } catch (Exception e) {
            e.printStackTrace();
            return Result.err().msg("；该条码暂无补货数据");
        }
    }

    public Boolean insertBusinDataTask(Map<String, String> detailVos, String startPoint) {

        try {
            //生成作业任务
            BusinDataTask task = new BusinDataTask();
            String taskCode = "T" + DateUtils.dateTimeNow();
            task.setTaskCode(taskCode);
            task.setTaskPath(startPoint);
            task.setTaskType(TaskTypeEnum.replenish_out.getValue());
            task.setPriority("2");
            task.setTaskStatus("0");
            task.setIsTop("0");
            task.setIsUrgent("0");
            task.setCreateTime(DateUtils.getNowDate());
            task.setFromRow(detailVos.get("locationRow"));
            task.setFromColumn(detailVos.get("locationColumn"));
            task.setFromLayer(detailVos.get("layer"));
            task.setTunnel(detailVos.get("tunnel"));
            task.setContainerId(Long.valueOf(detailVos.get("containerCode")));
            task.setLocationId(Long.valueOf(detailVos.get("locationId")));
            businDataTaskMapper.insertBusinDataTask(task);

            Long taskId = task.getId();
            if (detailVos.get("goodsNo").contains(",")) {
                String[] goodsNoStr = detailVos.get("goodsNo").split(",");
                String[] qrCodeStr = detailVos.get("qrCode").split(",");
                for (int i = 0; i < goodsNoStr.length; i++) {
                    BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                    taskGoods.setGoodsNo(goodsNoStr[i]);
                    taskGoods.setTaskCode(taskId);
                    taskGoods.setQrCode(qrCodeStr[i]);
                    taskGoods.setBranchId(Long.valueOf(detailVos.get("branchId")));
                    iBusinDataTaskGoodsService.save(taskGoods);
                }
            } else {
                BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
                taskGoods.setGoodsNo(detailVos.get("goodsNo"));
                taskGoods.setTaskCode(taskId);
                taskGoods.setQrCode(detailVos.get("qrCode"));
                taskGoods.setBranchId(Long.valueOf(detailVos.get("branchId")));
                iBusinDataTaskGoodsService.save(taskGoods);
            }

            //添加货位预占和库存预占
            //获取货位信息
            BaseLocation location = iBaseLocationService.getById(detailVos.get("locationId"));
            location.setLocationStatus("4");
            iBaseLocationService.updateById(location);
            //根据货位拿到库存信息
            List<SysStockDetail> sysStockDetailList = sysStockDetailMapper.getStockDetailByLocationId(String.valueOf(location.getId()));
            sysStockDetailList.stream().forEach(e -> {
                e.setOutQty(1);
            });
            //给库存添加出货预占
            iSysStockDetailService.updateBatchById(sysStockDetailList);
            //添加巷道任务数和总任务数
            tunnelTaskUtil.addOutboundTaskNum(detailVos.get("tunnel"));
            //任务添加巷道号
            task.setTunnel(detailVos.get("tunnel"));
            //任务添加plcid
            task.setDpsNoOne(Long.valueOf(isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.LK_plc_id)));
            //添加plc堆垛机id
            //根据巷道号获取堆垛机id
            BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
            pointQueryBo.setTunnel(detailVos.get("tunnel"));
            pointQueryBo.setDevType("1");
            pointQueryBo.setDirection("0");
            BaseDevicePlcVo baseDevicePlcVo = baseLocationPlcMapper.selectBaseDevicePlc(pointQueryBo);
            task.setDpsNoTwo(baseDevicePlcVo.getPlcId());
            //更新任务
            iBusinDataTaskService.updateById(task);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    @Override
    public Long insertBusinDataTask(BusinDataTask businDataTask) {
        return businDataTaskMapper.insertBusinDataTask(businDataTask);
    }

    @Override
    public BusinDataTask getBusinDataTaskByQrCode(String qrCode) {
        //获取条码信息
        BusinDataTask businDataTask = (BusinDataTask) redisTemplate.opsForValue().get(RedisConstant.redisTaskData + qrCode);
        if (businDataTask == null) {
            businDataTask = businDataTaskMapper.selectBusinDataTaskByQrcode(qrCode);
        }
        return businDataTask;
    }

    @Override
    public BusinDataTask getBusinDataTaskByTraverseDate(Date traverseDate) {
        BusinDataTask businDataTask = businDataTaskMapper.getBusinDataTaskByTraverseDate(traverseDate);
        return businDataTask;
    }

    @Override
    public List<BusinDataTaskVo> selectBusinDataTask(BusinTaskQueryBo bo) {
        return businDataTaskMapper.selectBusinDataTask(bo);
    }

    @Override
    public List<BusinDataTaskVo> selectBusinDataTask1(BusinTaskQueryBo bo) {
        return businDataTaskMapper.selectBusinDataTask1(bo);
    }

    @Override
    public List<BusinDataTaskVo> selectOutBusinDataTask(BusinTaskQueryBo bo) {
        return businDataTaskMapper.selectOutBusinDataTask(bo);
    }

    /**
     * 返回巷道，堆垛机编号 货位信息
     *
     * @return
     */


    @Transactional(rollbackFor = Exception.class)
    public synchronized BusinTaskExeBo outboundInfo_old(List<BusinDataTaskGoodsVo> goods, String id) {
        log.info("要出库的保险杠信息：" + JsonUtil.toJSONString(goods));
        //获取任务信息
        BusinDataTask businDataTask = iBusinDataTaskService.getById(id);
        //如果这次是二次分配货位那么需要将原货位的状态由已分配改为有物料,将库存明细表改为原装太
//        if (businDataTask.getLocationId()!=null&&businDataTask.getLocationId()!=0L){
//            BaseLocation byId = baseLocationService.getById(businDataTask.getLocationId());
//            byId.setLocationStatus("1");
//            baseLocationService.updateById(byId);
//            List<SysStockDetail> sysStockDetails = iSysStockDetailService.list(new LambdaQueryWrapper<SysStockDetail>()
//                    .eq(SysStockDetail::getLocationId, byId.getId())
//                    .eq(SysStockDetail::getQty, 1)
//            .eq(SysStockDetail::getOutQty,1));
//            for (SysStockDetail systockDetail: sysStockDetails
//            ) {
//                systockDetail.setOutQty(0);
//            }
//            iSysStockDetailService.updateBatchById(sysStockDetails);
//
//        }


        List<BusinDataTask> taskList = new ArrayList<>();
        BusinDataTaskGoodsVo good = goods.get(0);
        log.info("要出库的保险杠编号：" + good.getGoodsNo());
        //根据物料查询所在仓库
        List<BaseLocationVo> tunnelVo = baseLocationService.getTUunnel(good.getGoodsNo());
        //log.info("查询到的保险杠所在的货位信息："+JsonUtil.toJSONString(tunnelVo));
        List<String> tunnelall = tunnelVo.stream().map(e -> e.getTunnel()).collect(Collectors.toList());
        // log.info("查询到保险杠所在的巷道："+JsonUtil.toJSONString(tunnelall));
        //拿到任务数最少的巷道
        String tunnelone = this.quickSort(tunnelall);
        log.info("任务数最少的巷道：" + tunnelone);
        List<BaseLocationVo> tunnelLocation = tunnelVo.stream().filter(e -> e.getTunnel().equals(tunnelone)).collect(Collectors.toList());
        //  log.info("当前巷道的有库存的货位信息："+JsonUtil.toJSONString(tunnelLocation));
        List<Long> listlocationId = new ArrayList<>();
        //生成出库明细
        BusinTaskExeBo exeBo = new BusinTaskExeBo();
        exeBo.setTaskCode(businDataTask.getId());
        exeBo.setBusinDataTaskGoodsVo(goods);
        exeBo.setTransNo("2");
        exeBo.setTransQual("2");
        //如果是双深位 查看外侧的货位是否有托盘
        for (BaseLocationVo baseLovationVO : tunnelLocation) {
            if (baseLovationVO.getIsDeep().equals("2")) {
                BaseLocation one = null;
                one = baseLocationService.getOne(new LambdaQueryWrapper<BaseLocation>()
                        .eq(BaseLocation::getRoute, baseLovationVO.getRoute())
                        .eq(BaseLocation::getIsDeep, "1")
                        .eq(BaseLocation::getTunnel, baseLovationVO.getTunnel())
                        .eq(BaseLocation::getAreaId, baseLovationVO.getAreaId()));
                if (one != null && (one.getLocationStatus().equals("4") || one.getLocationStatus().equals("1") || one.getLocationStatus().equals("2"))) {
                    listlocationId.add(baseLovationVO.getId());
                }
            }
        }
        log.info("单深位有库存：" + JsonUtil.toJSONString(listlocationId));
        if (listlocationId.size() > 0) {
            for (int i = 0; i < tunnelLocation.size(); i++) {
                int number = i;
                listlocationId.stream().forEach(
                        e -> {
                            if (e.equals(tunnelLocation.get(number).getId())) {
                                tunnelLocation.remove(number);
                            }
                        }
                );
            }
        }
        if (tunnelLocation.size() == 0) {
            log.info("没有可出货的货位了:" + good.getGoodsNo());
            return exeBo;
        }

        //根据巷道分配货位
        BaseLocationVo baseLocationVo = tunnelLocation.get(0);
        exeBo.setBaseLocationVo(baseLocationVo);

//        //根据货位拿到库存信息
//        List<SysStockDetail> sysStockDetailList = sysStockDetailMapper.getStockDetailByLocationId(String.valueOf(baseLocationVo.getId()));
//        sysStockDetailList.stream().forEach(e->{
//            e.setOutQty(1);
//        });
//        //给库存添加出货预占
//        iSysStockDetailService.updateBatchById(sysStockDetailList);
        //
        Long stkPlcId = null;
        Long plcId = null;
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
        pointQueryBo.setTunnel(baseLocationVo.getTunnel());
        pointQueryBo.setDirection("0");
        List<BasePointDeviceVo> basePointDeviceVos = new ArrayList<>();
        plcId = Long.valueOf(isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.LK_plc_id));
        //获取巷道对应的堆垛机信息
        pointQueryBo.setDevType("1");
        BaseDevicePlcVo baseDevicePlcVo = baseLocationPlcMapper.selectBaseDevicePlc(pointQueryBo);
        stkPlcId = baseDevicePlcVo.getPlcId();


        //回填任务相关数据
        if (ObjectUtils.isEmpty(businDataTask.getFromLayer())) {
            businDataTask.setFromColumn(String.valueOf(baseLocationVo.getLocationColumn()));
            businDataTask.setFromLayer(baseLocationVo.getLayer());
            businDataTask.setFromRow(baseLocationVo.getLocationRow());
            businDataTask.setDevId(baseLocationVo.getDevId());
            businDataTask.setTunnel(baseLocationVo.getTunnel());
            businDataTask.setDpsNoOne(plcId);
            businDataTask.setDpsNoTwo(stkPlcId);
            //拿到库存里的治具编号(不分体的每个保险杠在一个货位一个任务,分体的只有一个任务一个货位所以只随机拿到一个库存信息的治具号就可以)
            //businDataTask.setContainerId(sysStockDetailList.get(0).getContainerCode());
            //测试使用货位id
            businDataTask.setLocationId(baseLocationVo.getId());
            iBusinDataTaskService.updateById(businDataTask);
        }

//        baseLocationVo.setLocationStatus("4");
//        baseLocationService.updateById(BeanUtil.toBean(baseLocationVo, BaseLocation.class));


        List<BusinDataTaskGoods> businDataTaskGoodsList = iBusinDataTaskGoodsService.list(new LambdaQueryWrapper<BusinDataTaskGoods>()
                .eq(BusinDataTaskGoods::getTaskCode, id));

        //根据货位查询物料信息
//        SysStockDetailQueryBo stockDetailQueryBo = new SysStockDetailQueryBo();
//        stockDetailQueryBo.setLocationId(baseLocationVo.getId());
//        stockDetailQueryBo.setQty(new BigDecimal("1"));
        List<SysStockDetail> sysStockDetailList = iSysStockDetailService.list(new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getLocationId, baseLocationVo.getId())
                .eq(SysStockDetail::getQty, 1)
                .isNull(SysStockDetail::getOutQty));
//        List<SysStockDetail> sysStockDetailList = iSysStockDetailService.queryList(stockDetailQueryBo);
//        System.out.println("是否相等"+sysStockDetailList.get(0).getGoodsNo().equals(businDataTaskGoodsList.get(0).getGoodsNo()));
        for (SysStockDetail stockDetail : sysStockDetailList) {
            businDataTaskGoodsList.stream().forEach(
                    e -> {
                        log.info("内部是否相等:" + e.getGoodsNo().equals(stockDetail.getGoodsNo()) + "任务保险杠编码：" + e.getGoodsNo() + " 库存保险杠条码：" + stockDetail.getGoodsNo());
                        if (e.getGoodsNo().equals(stockDetail.getGoodsNo())) {
                            e.setQrCode(stockDetail.getQrCode());
                        }
                    }
            );
        }
        //更新任务物料明细
        iBusinDataTaskGoodsService.saveOrUpdateBatch(businDataTaskGoodsList);
//        //取待补货区上的货不满足应发任务的货物时
//        if (sysStockDetailList.size()<=businDataTaskGoodsList.size()){
//            sysStockDetailList.stream().forEach(
//                    e->{
//                        for (int i=0;i<businDataTaskGoodsList.size();i++
//                             ) {
//                            BusinDataTaskGoods businDataTaskGoods=businDataTaskGoodsList.get(i);
//                            if (e.getGoodsNo().equals(businDataTaskGoods.getGoodsNo())){
//                                businDataTaskGoodsList.remove(i);
//                            }
//                        }
//                    }
//            );
//        }
//
//        if (businDataTaskGoodsList.size()>0){
//            //创建新的任务
//            String taskCode = "TR" + DateUtils.dateTimeNow();
//            String transId = com.shkj.common.utils.uuid.UUID.randomUUID().toString();
//            BusinTaskAddBo businTaskAddBo =new BusinTaskAddBo();
//            businTaskAddBo.setTaskCode(taskCode);
//            businTaskAddBo.setPlcId(businDataTask.getPlcId());
//            businTaskAddBo.setTaskStatus(TaskStatusEnum.wait_put.getValue());
//            businTaskAddBo.setTaskType(businDataTask.getTaskType());
//            businTaskAddBo.setCreateTime(DateUtils.getNowDate());
//            businTaskAddBo.setBatch(DateUtils.getDate());
//            businTaskAddBo.setTransId(transId);
//            businTaskAddBo.setAssociatedTasksId(id);
////            businTaskAddBo.setContainerId(businDataTask.getContainerId());
//            businTaskAddBo.setTaskPath(businDataTask.getTaskPath());
//            BusinDataTask newbusinDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);
//            iBusinDataTaskService.insertBusinTask(newbusinDataTask);
////            businDataTask.setAssociatedTasksId(newbusinDataTask.getId().toString());
//            iBusinDataTaskService.updateById(businDataTask);
//            //将原任务为出货的物料与新任务绑定
//            businDataTaskGoodsList.stream().forEach(
//                    e->{
//                        e.setTaskCode(newbusinDataTask.getId());
//                    }
//            );
//            iBusinDataTaskGoodsService.updateBatchById(businDataTaskGoodsList);
//        }


//        taskList.add(businDataTask);
        return exeBo;
    }


    /**
     * 返回巷道，堆垛机编号 货位信息
     *
     * @return
     */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized BusinTaskExeBo outboundInfo(List<BusinDataTaskGoodsVo> goods, String id) {
        log.info("要出库的保险杠信息：" + JsonUtil.toJSONString(goods));
        //获取任务信息
        BusinDataTask businDataTask = iBusinDataTaskService.getById(id);
        //如果这次是二次分配货位那么需要将原货位的状态由已分配改为有物料,将库存明细表改为原装太
//        if (businDataTask.getLocationId()!=null&&businDataTask.getLocationId()!=0L){
//            BaseLocation byId = baseLocationService.getById(businDataTask.getLocationId());
//            byId.setLocationStatus("1");
//            baseLocationService.updateById(byId);
//            List<SysStockDetail> sysStockDetails = iSysStockDetailService.list(new LambdaQueryWrapper<SysStockDetail>()
//                    .eq(SysStockDetail::getLocationId, byId.getId())
//                    .eq(SysStockDetail::getQty, 1)
//            .eq(SysStockDetail::getOutQty,1));
//            for (SysStockDetail systockDetail: sysStockDetails
//            ) {
//                systockDetail.setOutQty(0);
//            }
//            iSysStockDetailService.updateBatchById(sysStockDetails);
//
//        }


        List<BusinDataTask> taskList = new ArrayList<>();
        BusinDataTaskGoodsVo good = goods.get(0);
        log.info("要出库的保险杠编号：" + good.getGoodsNo());
        //根据物料查询所在仓库

        // TODO: 2024/6/27  出库时查询巷道任务数最少及库存量最多的
        List<BaseLocationVo> tunnelVo = baseLocationService.getTUunnel(good.getGoodsNo());
        if (tunnelVo != null && tunnelVo.size() == 0) {
            log.info("要出库的保险杠编号：" + good.getGoodsNo());
            return null;
        }
        Map<String, Long> tunnelLocQtyDic = tunnelVo.stream().collect(Collectors.groupingBy(BaseLocationVo::getTunnel, Collectors.counting()));
        //排序后的巷道货位数（降序）
        Map<String, Integer> tunnelLocQtyDicSort = new LinkedHashMap<>();
        tunnelLocQtyDic.entrySet().stream().sorted(Map.Entry.<String, Long>comparingByValue().reversed()).forEachOrdered(e -> tunnelLocQtyDicSort.put(e.getKey(), e.getValue().intValue()));
        //log.info("查询到的保险杠所在的货位信息："+JsonUtil.toJSONString(tunnelVo));
        List<String> tunnelall = tunnelVo.stream().map(e -> e.getTunnel()).collect(Collectors.toList());
        //  log.info("查询到保险杠所在的巷道："+JsonUtil.toJSONString(tunnelall));
        //拿到任务数最少的巷道并且库存量是最大的
        String tunnelone = this.quickSortTaskQty(tunnelLocQtyDicSort);
        log.info("任务数最少的巷道：" + tunnelone);
        List<BaseLocationVo> tunnelLocation = tunnelVo.stream().filter(e -> e.getTunnel().equals(tunnelone)).collect(Collectors.toList());
        //log.info("当前巷道的有库存的货位信息："+JsonUtil.toJSONString(tunnelLocation));
        List<Long> listlocationId = new ArrayList<>();
        //生成出库明细
        BusinTaskExeBo exeBo = new BusinTaskExeBo();
        exeBo.setTaskCode(businDataTask.getId());
        exeBo.setBusinDataTaskGoodsVo(goods);
        exeBo.setTransNo("2");
        exeBo.setTransQual("2");
        //如果是双深位 查看外侧的货位是否有托盘
        for (BaseLocationVo baseLovationVO : tunnelLocation) {
            if (baseLovationVO.getIsDeep().equals("2")) {
                BaseLocation one = null;
                one = baseLocationService.getOne(new LambdaQueryWrapper<BaseLocation>()
                        .eq(BaseLocation::getRoute, baseLovationVO.getRoute())
                        .eq(BaseLocation::getIsDeep, "1")
                        .eq(BaseLocation::getTunnel, baseLovationVO.getTunnel())
                        .eq(BaseLocation::getAreaId, baseLovationVO.getAreaId()));
                if (one != null && (one.getLocationStatus().equals("4") || one.getLocationStatus().equals("1") || one.getLocationStatus().equals("2"))) {
                    listlocationId.add(baseLovationVO.getId());
                }
            }
        }
        log.info("单深位有库存：" + JsonUtil.toJSONString(listlocationId));
        if (listlocationId.size() > 0) {
            for (int i = 0; i < tunnelLocation.size(); i++) {
                int number = i;
                listlocationId.stream().forEach(
                        e -> {
                            if (e.equals(tunnelLocation.get(number).getId())) {
                                tunnelLocation.remove(number);
                            }
                        }
                );
            }
        }
        if (tunnelLocation.size() == 0) {
            log.error("没有可出货的货位了:" + good.getGoodsNo());
            return exeBo;
        }

        //根据巷道分配货位
        BaseLocationVo baseLocationVo = tunnelLocation.get(0);
        exeBo.setBaseLocationVo(baseLocationVo);

//        //根据货位拿到库存信息
//        List<SysStockDetail> sysStockDetailList = sysStockDetailMapper.getStockDetailByLocationId(String.valueOf(baseLocationVo.getId()));
//        sysStockDetailList.stream().forEach(e->{
//            e.setOutQty(1);
//        });
//        //给库存添加出货预占
//        iSysStockDetailService.updateBatchById(sysStockDetailList);
        //
        Long stkPlcId = null;
        Long plcId = null;
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
        pointQueryBo.setTunnel(baseLocationVo.getTunnel());
        pointQueryBo.setDirection("0");
        List<BasePointDeviceVo> basePointDeviceVos = new ArrayList<>();
        plcId = Long.valueOf(isysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.LK_plc_id));
        //获取巷道对应的堆垛机信息
        pointQueryBo.setDevType("1");
        BaseDevicePlcVo baseDevicePlcVo = baseLocationPlcMapper.selectBaseDevicePlc(pointQueryBo);
        stkPlcId = baseDevicePlcVo.getPlcId();

        //回填任务相关数据
        if (ObjectUtils.isEmpty(businDataTask.getFromLayer())) {
            businDataTask.setFromColumn(String.valueOf(baseLocationVo.getLocationColumn()));
            businDataTask.setFromLayer(baseLocationVo.getLayer());
            businDataTask.setFromRow(baseLocationVo.getLocationRow());
            businDataTask.setDevId(baseLocationVo.getDevId());
            businDataTask.setTunnel(baseLocationVo.getTunnel());
            businDataTask.setDpsNoOne(plcId);
            businDataTask.setDpsNoTwo(stkPlcId);
            //拿到库存里的治具编号(不分体的每个保险杠在一个货位一个任务,分体的只有一个任务一个货位所以只随机拿到一个库存信息的治具号就可以)
            //businDataTask.setContainerId(sysStockDetailList.get(0).getContainerCode());
            //测试使用货位id
            businDataTask.setLocationId(baseLocationVo.getId());
            iBusinDataTaskService.updateById(businDataTask);
        }

//        baseLocationVo.setLocationStatus("4");
//        baseLocationService.updateById(BeanUtil.toBean(baseLocationVo, BaseLocation.class));


        List<BusinDataTaskGoods> businDataTaskGoodsList = iBusinDataTaskGoodsService.list(new LambdaQueryWrapper<BusinDataTaskGoods>()
                .eq(BusinDataTaskGoods::getTaskCode, id));

        //根据货位查询物料信息
//        SysStockDetailQueryBo stockDetailQueryBo = new SysStockDetailQueryBo();
//        stockDetailQueryBo.setLocationId(baseLocationVo.getId());
//        stockDetailQueryBo.setQty(new BigDecimal("1"));
        List<SysStockDetail> sysStockDetailList = iSysStockDetailService.list(new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getLocationId, baseLocationVo.getId())
                .eq(SysStockDetail::getQty, 1)
                .isNull(SysStockDetail::getOutQty));
//        List<SysStockDetail> sysStockDetailList = iSysStockDetailService.queryList(stockDetailQueryBo);
//        System.out.println("是否相等"+sysStockDetailList.get(0).getGoodsNo().equals(businDataTaskGoodsList.get(0).getGoodsNo()));
        for (SysStockDetail stockDetail : sysStockDetailList) {
            businDataTaskGoodsList.stream().forEach(
                    e -> {
                        log.info("内部是否相等:" + e.getGoodsNo().equals(stockDetail.getGoodsNo()) + "任务保险杠编码：" + e.getGoodsNo() + " 库存保险杠条码：" + stockDetail.getGoodsNo());
                        if (e.getGoodsNo().equals(stockDetail.getGoodsNo())) {
                            e.setQrCode(stockDetail.getQrCode());
                        }
                    }
            );
        }
        //更新任务物料明细
        iBusinDataTaskGoodsService.saveOrUpdateBatch(businDataTaskGoodsList);
//        //取待补货区上的货不满足应发任务的货物时
//        if (sysStockDetailList.size()<=businDataTaskGoodsList.size()){
//            sysStockDetailList.stream().forEach(
//                    e->{
//                        for (int i=0;i<businDataTaskGoodsList.size();i++
//                             ) {
//                            BusinDataTaskGoods businDataTaskGoods=businDataTaskGoodsList.get(i);
//                            if (e.getGoodsNo().equals(businDataTaskGoods.getGoodsNo())){
//                                businDataTaskGoodsList.remove(i);
//                            }
//                        }
//                    }
//            );
//        }
//
//        if (businDataTaskGoodsList.size()>0){
//            //创建新的任务
//            String taskCode = "TR" + DateUtils.dateTimeNow();
//            String transId = com.shkj.common.utils.uuid.UUID.randomUUID().toString();
//            BusinTaskAddBo businTaskAddBo =new BusinTaskAddBo();
//            businTaskAddBo.setTaskCode(taskCode);
//            businTaskAddBo.setPlcId(businDataTask.getPlcId());
//            businTaskAddBo.setTaskStatus(TaskStatusEnum.wait_put.getValue());
//            businTaskAddBo.setTaskType(businDataTask.getTaskType());
//            businTaskAddBo.setCreateTime(DateUtils.getNowDate());
//            businTaskAddBo.setBatch(DateUtils.getDate());
//            businTaskAddBo.setTransId(transId);
//            businTaskAddBo.setAssociatedTasksId(id);
////            businTaskAddBo.setContainerId(businDataTask.getContainerId());
//            businTaskAddBo.setTaskPath(businDataTask.getTaskPath());
//            BusinDataTask newbusinDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);
//            iBusinDataTaskService.insertBusinTask(newbusinDataTask);
////            businDataTask.setAssociatedTasksId(newbusinDataTask.getId().toString());
//            iBusinDataTaskService.updateById(businDataTask);
//            //将原任务为出货的物料与新任务绑定
//            businDataTaskGoodsList.stream().forEach(
//                    e->{
//                        e.setTaskCode(newbusinDataTask.getId());
//                    }
//            );
//            iBusinDataTaskGoodsService.updateBatchById(businDataTaskGoodsList);
//        }


//        taskList.add(businDataTask);
        return exeBo;
    }

    /**
     * 返回任务数最少及库存量最大的
     *
     * @param tunnelLocQtyDicSort
     * @return
     */
    public String quickSortTaskQty(Map<String, Integer> tunnelLocQtyDicSort) {

        List<TunnelTaskQtyVo> taskQtyVoList = new ArrayList<>();
        for (String tunnel : tunnelLocQtyDicSort.keySet()) {
            TunnelTaskQtyVo tunnelTaskQtyVo = new TunnelTaskQtyVo();
            Integer totalTaskNum = tunnelTaskUtil.getTotalTaskNum(tunnel, 1);
            Integer tunnelLocQty = tunnelLocQtyDicSort.get(tunnel);
            tunnelTaskQtyVo.setTunnel(tunnel);
            tunnelTaskQtyVo.setTaskNum(totalTaskNum);
            tunnelTaskQtyVo.setLocQty(tunnelLocQty);
            taskQtyVoList.add(tunnelTaskQtyVo);

        }
        TunnelTaskQtyVo tunnelTaskQtyVo = taskQtyVoList.stream().sorted(Comparator.comparing(TunnelTaskQtyVo::getTaskNum).thenComparing(TunnelTaskQtyVo::getLocQty, Comparator.reverseOrder())).findFirst().orElse(null);

        return tunnelTaskQtyVo.getTunnel();
    }

    /**
     * 返回任务数最少的巷道号
     *
     * @param tunnelall
     * @return
     */

    public String quickSort(List<String> tunnelall) {
        String tunnel = "";
        Map<String, Integer> tunnelmap = new HashMap<>();

        tunnelall.stream().forEach(
                e -> {
                    tunnelmap.put(e, tunnelTaskUtil.getTotalTaskNum(e, 1));
                }
        );
        List<Integer> collect = tunnelmap.values().stream().sorted().collect(Collectors.toList());
        for (String key :
                tunnelmap.keySet()) {
            if (tunnelmap.get(key).equals(collect.get(0))) {
                tunnel = key;
            }

        }
        return tunnel;
    }

    @Override
    public List<DataScreeTaskqtyVo> getCurDateTaskQty() {
        return businDataTaskMapper.getCurDateTaskQty();
    }


    /**
     * 根据入库的物料，查询待出库的物料信息
     *
     * @param goods
     * @return
     */
    @Override
    public List<BusinDataTaskOutVo> selectOutBoundDataTask(String goods) {
        return businDataTaskMapper.selectOutBoundDataTask(goods);
    }

    /**
     * 任务管理查询页面接口
     *
     * @param bo 页面查询条件
     * @return
     */
    @Override
    public List<BusinDataTaskManageVo> selectTaskManagement(BusinTaskManageQueryBo bo) {
        List<BusinDataTaskManageVo> businDataTaskManageVos = businDataTaskMapper.selectTaskManagement(bo);
        return businDataTaskManageVos;
    }

    /**
     * 任务管理--取消任务
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> cancelTask(BusinTaskManageDistributeBo bo) {

        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getId, bo.getTaskId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (!businDataTask.getTaskStatus().equals("0")) {
            return Result.err().msg("此任务不可取消");
        }

        businDataTask.setTaskStatus("3");
        return this.updateById(businDataTask) ? Result.ok() : Result.err();


    }

    /**
     * 任务管理--重新下发
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> reissueTask(BusinTaskManageDistributeBo bo) {
        return null;
    }

    /**
     * 任务管理--立即下发
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> instantlyTask(BusinTaskManageDistributeBo bo) {
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getId, bo.getTaskId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        //改完为下发，走调度执行
        businDataTask.setTaskStatus("0");
        return this.updateById(businDataTask) ? Result.ok() : Result.err();
    }

    /**
     * 提升任务的优先级
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> elevatePriorityTask(BusinTaskManageDistributeBo bo) {
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getId, bo.getTaskId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (!businDataTask.getTaskStatus().equals("0")) {
            return Result.err().msg("此任务不可提升优先级");
        }
        //提升优先级
        businDataTask.setPriority("1");
        return this.updateById(businDataTask) ? Result.ok() : Result.err();
    }

    /**
     * 暂停任务
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> pauseTask(BusinTaskManageDistributeBo bo) {
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getId, bo.getTaskId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (!businDataTask.getTaskStatus().equals("0")) {
            return Result.err().msg("此任务不可暂停");
        }
        //任务暂停
        businDataTask.setTaskStatus("4");
        return this.updateById(businDataTask) ? Result.ok() : Result.err();
    }

    /**
     * 任务启用
     *
     * @param bo
     * @return
     */
    @Override
    public Result<Boolean> activeTask(BusinTaskManageDistributeBo bo) {
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getId, bo.getTaskId()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (!businDataTask.getTaskStatus().equals("4")) {
            return Result.err().msg("此任务不可启用");
        }
        //任务暂停
        businDataTask.setTaskStatus("0");
        return this.updateById(businDataTask) ? Result.ok() : Result.err();
    }


    @Override
    public List<BusinDataTask> queryinTask() {
        return this.baseMapper.queryinTask();
    }

    @Override
    public Boolean updateBatchById(List<BusinDataTask> businDataTasks) {
        return super.updateBatchById(businDataTasks);
    }

    @Override
    public Integer callContainerCount() {
        return this.baseMapper.callContainerCount();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result goAbnormal(Map map) {
        try {
            String tepairGroup = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.putoutexc_point);
            BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
            pointQueryBo.setGroupNo(tepairGroup);
            BasePointDeviceVo pointDevice = basePointDeviceMapper.selectBasePointByGroupno(pointQueryBo);
            String point = null;
            if (pointDevice == null) {
                return Result.err().msg("请维护出库异常点位信息");
            }
            point = pointDevice.getPointNo();
            List<BusinDataTaskVo> businDataTaskVos = businDataTaskMapper.gettaskAbnormal(point);
            BusinDataTaskVo businDataTaskVo = new BusinDataTaskVo();
            if (businDataTaskVos.size() <= 0) {
                return Result.err().msg("当前点位没有车辆");
            }

            businDataTaskVo = businDataTaskVos.get(0);
            Long containerId = businDataTaskVo.getContainerId();

            //创建任务,任务类型异常指定agv车辆
            BusinDataTask businDataTask = new BusinDataTask();
            int randomOperands = (int) Math.round(Math.random() * 1000);
            String taskCode = "T_" + DateUtils.dateTimeNow() + randomOperands;
            businDataTask.setTaskCode(taskCode);
            businDataTask.setTaskStatus("0");
            businDataTask.setTaskType("1");
            businDataTask.setTaskPath(businDataTaskVo.getTaskPath());
            businDataTask.setAgvNo(businDataTaskVo.getAgvNo());
            businDataTask.setContainerId(containerId);
            businDataTaskMapper.insertBusinDataTask(businDataTask);

            Long taskId = businDataTask.getId();

            String firstBarcode = map.get("one").toString();
            String secondBarcode = map.get("two").toString();
            String thirdBarcode = map.get("three").toString();

            List<BusinDataTaskGoods> goods = new ArrayList<>();

            if (!firstBarcode.isEmpty()) {
                BaseBarcodesIn barcodes_f = iBaseBarcodesInService.getBaseBarcodesByQrCode(firstBarcode);

                BusinDataTaskGoods firstGoods = new BusinDataTaskGoods();
                firstGoods.setQrCode(firstBarcode);
                firstGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                firstGoods.setTaskCode(taskId);
                firstGoods.setCreateTime(DateUtils.getNowDate());
                firstGoods.setGoodsNo(barcodes_f.getGoodsNo());
                firstGoods.setIsPunching(barcodes_f.getIsPunching());
                firstGoods.setIsRepair(barcodes_f.getIsRepair());
                goods.add(firstGoods);
            }

            if (!secondBarcode.isEmpty()) {
                BaseBarcodesIn barcodes_s = iBaseBarcodesInService.getBaseBarcodesByQrCode(secondBarcode);
                BusinDataTaskGoods secondGoods = new BusinDataTaskGoods();
                secondGoods.setQrCode(secondBarcode);
                secondGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                secondGoods.setTaskCode(taskId);
                secondGoods.setCreateTime(DateUtils.getNowDate());
                secondGoods.setGoodsNo(barcodes_s.getGoodsNo());
                secondGoods.setIsPunching(barcodes_s.getIsPunching());
                secondGoods.setIsRepair(barcodes_s.getIsRepair());
                goods.add(secondGoods);
            }

            if (!thirdBarcode.isEmpty()) {
                BaseBarcodesIn barcodes_t = iBaseBarcodesInService.getBaseBarcodesByQrCode(thirdBarcode);
                BusinDataTaskGoods thirdGoods = new BusinDataTaskGoods();
                thirdGoods.setQrCode(thirdBarcode);
                thirdGoods.setBranchId(SecurityUtils.getCurrentBranchId());
                thirdGoods.setTaskCode(taskId);
                thirdGoods.setCreateTime(DateUtils.getNowDate());
                thirdGoods.setGoodsNo(barcodes_t.getGoodsNo());
                thirdGoods.setIsPunching(barcodes_t.getIsPunching());
                thirdGoods.setIsRepair(barcodes_t.getIsRepair());
                goods.add(thirdGoods);
            }

            //新增物料明细
            iBusinDataTaskGoodsService.saveOrUpdateBatch(goods);

            return Result.ok();
        } catch (Exception e) {
            e.printStackTrace();
            return Result.err();
        }
    }

    /**
     * 获取紧急出库的物料明细
     *
     * @return
     */
    @Override
    public List<BusinDataTaskGoodsVo> getEmergencyOutboundDtl() {
        List<BusinDataTaskGoodsVo> goodsVos = (List<BusinDataTaskGoodsVo>) redisTemplate.opsForValue().get(RedisConstant.redisEmergencyOutbound);
        return goodsVos;
    }

    /**
     * 紧急出库到达接驳口时，确认按钮
     *
     * @param bo
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> confirmEmergencyOutboundDtl(EmergencyOutboundAddBo bo) {

        Long taskId = bo.getTaskId();
        List<String> oldBoGoods = bo.getOldBo().getGoods();
        List<String> newBoGoods = bo.getNewBo().getGoods();
        boolean equals = false;
        if (oldBoGoods != null && newBoGoods != null) {
            equals = isEquals(oldBoGoods, newBoGoods);
        }
        BusinDataTask oldtask = iBusinDataTaskService.getById(bo.getTaskId());
        //获取紧急出库接驳点点位
        String fromPoint = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.urgency_out_point);
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
        String outPoint = "";

        pointQueryBo.setGroupNo(fromPoint);
        BasePointDeviceVo pointDeviceout = basePointDeviceMapper.selectBasePointByGroupno(pointQueryBo);
        if (pointDeviceout == null) {
            log.error("请维护紧急出库接驳点");
        }
        outPoint = pointDeviceout.getPointNo();
        //true 到货和取货一样，走空治具返回流程
        if (equals) {
            iBusinEnptyContainerService.emptyContainerFlowDir(outPoint, bo.getContainerId(), oldtask.getAgvNo(), null);
        } else {
            //部分取货,获取取货后剩余的物料，走入库流程
            List<String> diffGoods = new ArrayList<>(Sets.difference(Sets.newHashSet(oldBoGoods), Sets.newHashSet(newBoGoods)));

            BillTaskAddbo billTaskAddbo = new BillTaskAddbo();
            billTaskAddbo.setContainerCode(bo.getContainerId());
            billTaskAddbo.setStartPoint(outPoint);
            billTaskAddbo.setTaskType(TaskTypeEnum.replenish_in.getValue());
            List<BasinBarcodeInAddBo> barcodeInAddBos = bo.getOldBo().getBarcodeInAddBos();
            List<BasinBarcodeInAddBo> newBarcodes = new ArrayList<>();
            for (int i = 0; i < diffGoods.size(); i++) {
                int goodsI = i;
                barcodeInAddBos.stream().forEach(e -> {
                    if (e.getGoodsNo().equals(diffGoods.get(goodsI))) {
                        newBarcodes.add(e);
                    }
                });
            }
            billTaskAddbo.setBarcodesList(newBarcodes);
            Result taskidresult = iPutInOutStorageService.saveBillTaskIn(billTaskAddbo, null);

            //下发带有agv编号的命令 TODO
            Long newtaskId = (Long) taskidresult.getData();
            BusinDataTask newTask = iBusinDataTaskService.getById(newtaskId);
            runReplenishIn(newTask, oldtask.getAgvNo());

        }
        Result<Boolean> booleanResult = iPutInOutStorageService.reduceInventory(taskId, newBoGoods);
        //确认完成后，从redis中删除
        redisTemplate.delete(RedisConstant.redisEmergencyOutbound);

        return booleanResult;
    }

    @Override
    public Result CallAirFixture(String taskId) {
        //获取平库出库点位
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
        String tepairGroup = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.P_out01);
        pointQueryBo.setGroupNo(tepairGroup);
        BasePointDeviceVo pointDeviceout = basePointDeviceMapper.selectBasePointByGroupno(pointQueryBo);
        String topoint = pointDeviceout.getPointNo();
        String taskCode = "T" + DateUtils.dateTime();
        BusinTaskAddBo businTaskAddBo = new BusinTaskAddBo();
        businTaskAddBo.setTaskType(TaskTypeEnum.call_container.getValue());
        businTaskAddBo.setTaskCode(taskCode);
        businTaskAddBo.setTaskStatus(TaskStatusEnum.wait_put.getValue());
        businTaskAddBo.setIsDown(String.valueOf(RCSTaskTypeEnum.TO_B_PUT.getValue()));
        businTaskAddBo.setTaskPath(topoint);
        BusinDataTask businDataTask = BeanUtil.toBean(businTaskAddBo, BusinDataTask.class);

        this.baseMapper.insertBusinDataTask(businDataTask);
        this.baseMapper.updateById(this.baseMapper.selectById(taskId).setTaskStatus("2"));
        return Result.ok();
    }

    @Override
    public Result CallRcs(BaseDeriveTraverseVo baseDeriveTraverseVo) {
        BaseContainer baseContainer = iBaseContainerService.getOne(new LambdaQueryWrapper<BaseContainer>()
                .eq(BaseContainer::getContainerCode, baseDeriveTraverseVo.getContainerId()));
        baseDeriveTraverseVo.setContainerId(String.valueOf(baseContainer.getId()));
        BusinDataTask dataTask = this.getOne(new LambdaQueryWrapper<BusinDataTask>()
                .eq(BusinDataTask::getContainerId, baseContainer.getId())
                .eq(BusinDataTask::getTaskStatus, "1")
                .eq(BusinDataTask::getTaskType, "15")
                .orderByDesc(BusinDataTask::getUpdateTime)
                .last("limit 1"));
        String fromPoint = dataTask.getTaskPath();
        String agvno = dataTask.getAgvNo();
        BusinDataTask businDataTask = new BusinDataTask();

        String taskCode = "T_" + DateUtils.dateTimeNow();
        businDataTask.setTaskCode(taskCode);
        businDataTask.setTaskStatus(TaskStatusEnum.wait_put.getValue());
        businDataTask.setTaskType(TaskTypeEnum.thirteen_out.getValue());
        businDataTask.setContainerId(Long.valueOf(baseDeriveTraverseVo.getContainerId()));
        businDataTask.setAgvNo(agvno);
        businDataTaskMapper.insertBusinDataTask(businDataTask);
        //添加任务产品明细
        List<BusinDataTaskGoods> businDataTaskGoodsList = new ArrayList<>();
        List<BusinDataTaskGoodsVo> businDataTaskGoodsVoList = baseDeriveTraverseVo.getBusinDataTaskGoodsList();
        for (BusinDataTaskGoodsVo businDataTaskGoodsVo : businDataTaskGoodsVoList
        ) {
            BusinDataTaskGoods taskGoods = new BusinDataTaskGoods();
            taskGoods.setGoodsNo(businDataTaskGoodsVo.getGoodsNo());
            taskGoods.setQrCode(businDataTaskGoodsVo.getQrCode());
            taskGoods.setTaskCode(businDataTask.getId());
            businDataTaskGoodsList.add(taskGoods);
        }
        iBusinDataTaskGoodsService.saveBatch(businDataTaskGoodsList);

        //获取出库点位
        String pointout = sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.Manual_drop_point);
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();

        pointQueryBo.setGroupNo(pointout);
        List<BasePointDeviceVo> pointDeviceout = basePointDeviceMapper.getBasePointByGroupNoList(pointQueryBo);
        List<String> dbTableColumnNames = pointDeviceout.stream().map(BasePointDeviceVo::getPointNo).collect(Collectors.toList());
        String urgency = null;
        String urgencyBefore = null;
        String urgencyAfter = null;
        for (String str : dbTableColumnNames
        ) {
            if (str.equals(ParameterConstants.ParameterSystem.assemble_point_after)) {
                urgencyAfter = str;
            }

            if (str.equals(ParameterConstants.ParameterSystem.assemble_point_before)) {
                urgencyBefore = str;
            }
        }

        int assemblePointTypeBefore =
                ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.assemblePointBeforeTaskCount))
                        ? Integer.parseInt(redisTemplate.opsForValue().get(RedisConstant.assemblePointBeforeTaskCount).toString()) : 0;

        int assemblePointTypeAfter =
                ObjectUtils.isNotEmpty(redisTemplate.opsForValue().get(RedisConstant.assemblePointAfterTaskCount))
                        ? Integer.parseInt(redisTemplate.opsForValue().get(RedisConstant.assemblePointAfterTaskCount).toString()) : 0;


        //TODO 判断平库出库的是分体杠还是不分提的
        if (businDataTaskGoodsVoList.size() == 1) {
            BaseGoodsData baseGoodsData = iBaseGoodsDataService.getOne(new LambdaQueryWrapper<BaseGoodsData>()
                    .eq(BaseGoodsData::getGoodsNo, businDataTaskGoodsVoList.get(0).getGoodsNo()));
            if (("0").equals(baseGoodsData.getLocation())) {
                urgency = urgencyBefore;
            } else if (("1").equals(baseGoodsData.getLocation())) {
                urgency = urgencyAfter;
            }
        } else {
            if (assemblePointTypeBefore > assemblePointTypeAfter) {
                urgency = urgencyAfter;
            } else if (assemblePointTypeBefore < assemblePointTypeAfter) {
                urgency = urgencyBefore;
            } else if (assemblePointTypeBefore == assemblePointTypeAfter) {
                urgency = urgencyBefore;
            }
        }

        //生成出库明细
        BusinTaskExeBo exeBo = new BusinTaskExeBo();
        exeBo.setTaskCode(businDataTask.getId());
        exeBo.setBusinDataTaskGoodsVo(baseDeriveTraverseVo.getBusinDataTaskGoodsList());
        exeBo.setTransNo("2");
        exeBo.setTransQual("2");
        //库存预扣

        //呼叫agv
        int agvTaskType = Integer.valueOf(RCSTaskTypeEnum.TO_B_PUT.getValue());
        RcsCreateTaskDto dto = new RcsCreateTaskDto();
        Map<String, String> snPointMap = new HashMap<>();
        List<RcsIdList> idList = new ArrayList<>();

        dto.setMapId(1);
        dto.setTaskType(agvTaskType);
        dto.setRobotId(agvno);

        RcsIdList startId = new RcsIdList();
        RcsIdList endId = new RcsIdList();


        startId.setId(fromPoint);
        idList.add(startId);
        snPointMap.put("1", fromPoint);
        snPointMap.put("2", urgency);
        endId.setId(urgency);
        idList.add(endId);
        dto.setTargets(idList);
        Long taskId = businDataTask.getId();
        dto.setTaskId(taskId.toString());
        //更新目标点位和points
        businDataTask.setTaskPath(urgency);
        businDataTask.setPoints(JsonUtil.toJSONString(snPointMap));
        businDataTaskMapper.updateById(businDataTask);

        Result<Boolean> booleanResult = rcsUtil.rcsCreateTask(dto);
        if (booleanResult.getCode() == HttpStatus.SUCCESS.getCode()) {
            businDataTask.setTaskStatus(TaskStatusEnum.wait_callback.getValue());
            this.updateById(businDataTask);
            Result<String> billResult = iPutInOutStorageService.exeTaskPutinStorage(exeBo);
            //扣除库存
            List<BusinDataTaskGoodsVo> DataTaskGoodsList = baseDeriveTraverseVo.getBusinDataTaskGoodsList();
            for (BusinDataTaskGoodsVo dateTaskgoods : DataTaskGoodsList
            ) {
                SysStockDetail sysStockDetail = iSysStockDetailService.getOne(new LambdaQueryWrapper<SysStockDetail>()
                        .eq(SysStockDetail::getQrCode, dateTaskgoods.getQrCode())
                        .eq(SysStockDetail::getQty, "1")
                        .last("limit 1"));
                sysStockDetail.setQty(sysStockDetail.getQty().subtract(new BigDecimal("1")));
                iSysStockDetailService.updateById(sysStockDetail);
            }

        } else {
            businDataTask.setTaskStatus("-3");
            this.updateById(businDataTask);
        }
        return Result.ok();
    }

    @Override
    public Result QueryBarCode(String qrCode) {
//        Map<String, String> stringStringMap = JsonUtil.JsonStrToMap(qrCode);
//
//        qrCode=stringStringMap.get("qrCode");
        SysStockDetail sysStockDetail = iSysStockDetailService.getOne(new LambdaQueryWrapper<SysStockDetail>()
                .eq(SysStockDetail::getQrCode, qrCode)
                .isNull(SysStockDetail::getLocationId)
                .ne(SysStockDetail::getQty, "0"));
        if (ObjectUtils.isNotEmpty(sysStockDetail)) {
            //通过goodsNo拿到产品信息
            BaseGoodsData baseGoodsData = iBaseGoodsDataService.getOne(new LambdaQueryWrapper<BaseGoodsData>()
                    .eq(BaseGoodsData::getGoodsNo, sysStockDetail.getGoodsNo()));
            //通过车型和颜色拿到派生
//            BaseDerive baseDerive = iBaseDeriveService.getOne(new LambdaQueryWrapper<BaseDerive>()
//                    .eq(BaseDerive::getColor, baseGoodsData.getColor())
//                    .eq(BaseDerive::getVehicheModel, baseGoodsData.getVehicheModel()));
            BusinDataTaskGoodsVo businDataTaskGoodsVo = new BusinDataTaskGoodsVo();
            businDataTaskGoodsVo.setQrCode(qrCode);
            businDataTaskGoodsVo.setLocation(baseGoodsData.getLocation());
            businDataTaskGoodsVo.setVehicheModel(baseGoodsData.getVehicheModel());
            businDataTaskGoodsVo.setColor(baseGoodsData.getColor());
            businDataTaskGoodsVo.setGoodsNo(sysStockDetail.getGoodsNo());
//            businDataTaskGoodsVo.setDerive(baseDerive.getDerive());
            return Result.ok().data(businDataTaskGoodsVo);
        }
        return Result.err();
    }

    @Override
    public Result runReplenishIn(BusinDataTask businDataTask, String agvno) {

        //执行待补货区的任务
        Long plcId = 0L;
        Long stkPlcId = 0L;
        BasePointDeviceQueryBo pointQueryBo = new BasePointDeviceQueryBo();
        Long taskId = businDataTask.getId();
        //拿到起点
        String startPoint = businDataTask.getTaskPath();
        List<String> points = new ArrayList<>();

        Map<String, String> snPointMap = new HashMap<>(3);


        List<BasePointDeviceVo> basePointDeviceVos = new ArrayList<>();
        //点位对象
        BasePointDeviceVo basePointDeviceVo = null;
        //库位对象
        BaseLocationVo locationVo = null;
        // 获取待补货区域货位及巷道  暂时屏蔽，使用缓冲区
        Long outbound_point = Long.valueOf(sysParameterService.selectConfigByKey(ParameterConstants.ParameterSystem.outbound_point));
        List<BaseLocationVo> baseLocationVos = baseLocationMapper.getLocationByAreaId(19L);

        if (baseLocationVos.size() > 0) {
            locationVo = baseLocationVos.get(0);
        }
        businDataTask.setToColumn(locationVo.getLocationColumn());
        businDataTask.setToLayer(locationVo.getLayer());
        businDataTask.setToRow(locationVo.getLocationRow());

        String tunnel = locationVo.getTunnel();
        pointQueryBo = new BasePointDeviceQueryBo();
        pointQueryBo.setTunnel(tunnel);
        pointQueryBo.setDirection("0");
        //根据巷道查询巷道对应的入立库接驳口点位
        basePointDeviceVos = baseLocationPlcMapper.selectBasePointByGroupno(pointQueryBo);

        if (basePointDeviceVos.size() > 0) {
            basePointDeviceVo = basePointDeviceVos.get(0);
        }
        //获取巷道对应的堆垛机信息
        pointQueryBo.setDevType("1");
        BaseDevicePlcVo baseDevicePlcVo = baseLocationPlcMapper.selectBaseDevicePlc(pointQueryBo);
        stkPlcId = baseDevicePlcVo.getPlcId();
        points.add(startPoint);
        snPointMap.put("1", startPoint);

        plcId = basePointDeviceVo.getPlcId();

        String toPointNo = basePointDeviceVo.getPointNo();
        snPointMap.put("2", toPointNo);
        points.add(toPointNo);

        int agvTaskType = Integer.valueOf("25");
        businDataTask.setTunnel(tunnel);
        businDataTask.setPoints(JsonUtil.toJSONString(snPointMap));
        businDataTask.setIsDown(String.valueOf(agvTaskType));
        //呼叫AGV
        Result<Boolean> booleanResult = callAGV(taskId, agvTaskType, points, agvno);
        if (booleanResult.getCode() == HttpStatus.SUCCESS.getCode()) {
            businDataTask.setTaskStatus(TaskStatusEnum.wait_callback.getValue());
            businDataTask.setTaskPath(toPointNo);
        } else {
            if (redisTemplate.opsForValue().get(RedisConstant.redisAgvTaskerror + taskId) == null) {
                redisTemplate.opsForValue().set(RedisConstant.redisAgvTaskerror + taskId, 0);
            }
            Long a = Long.valueOf(String.valueOf(redisTemplate.opsForValue().get(RedisConstant.redisAgvTaskerror + taskId)));

            businDataTask.setTaskStatus(TaskStatusEnum.err.getValue());
            businDataTask.setExceptionMsg(booleanResult.getMsg());
            if (a < 3L) {
                long l = a + 1;
                redisTemplate.opsForValue().set(RedisConstant.redisAgvTaskerror + taskId, l);
            } else {
                businDataTask.setTaskStatus("-2");
            }
        }
        businDataTask.setDpsNoOne(plcId);
        businDataTask.setDpsNoTwo(stkPlcId);
        iBusinDataTaskService.saveOrUpdate(businDataTask);

        return null;
    }

    public Result<Boolean> callAGV(Long taskId, int taskType, List<String> points, String agvno) {
        AGVMoveBo moveBo = new AGVMoveBo();
        moveBo.setTaskId(taskId);
        moveBo.setTaskType(taskType);
        moveBo.setPoints(points);
        moveBo.setRobotId(agvno);
        Result<Boolean> booleanResult = rcsUtil.moveByAGV(moveBo);
        return booleanResult;
    }


    /**
     * 比较两个List的数据是否一样
     *
     * @param list1
     * @param list2
     * @param <T>
     * @return
     */
    public <T extends Comparable<T>> boolean isEquals(List<T> list1, List<T> list2) {
        if (list1.size() != list2.size()) {
            return false;
        }
        list1 = new ArrayList<T>(list1);
        list2 = new ArrayList<T>(list2);
        Collections.sort(list1);
        Collections.sort(list2);
        return list1.equals(list2);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Result<Boolean> addMoveTask(BusinStockMoveDAddBo bo) {
        /**
         * 1.巷道内移库
         *  1.1 生成巷道内移库任务，任务类型为16 给堆垛机下发任务（货位对货位任务）
         *  1.2 预占库存状态，移入移出货位
         *  1.2 堆垛机完成后，增加相应的库存信息
         *
         * 2.跨巷道移库
         * 2.1 生成跨巷道移库任务，任务类型为9，给堆垛机下发任务（货位对输送线任务）
         * 2.1 预占库存状态，移入移出货位
         * 2.2 AGV目标货位到移库巷道的入库输送线接驳点
         * 2.3 agv放货完成时，写入任务号；
         * 2.4 堆垛机放货完成时，处理库存
         */

        // 查询移出货位是否有库存
        Long outLocationId = bo.getOutLocationId();
        SysStockDetailQueryBo stockDetailQueryBo = new SysStockDetailQueryBo();
        stockDetailQueryBo.setLocationId(outLocationId);
        List<SysStockDetailVo> sysStockDetailVos = iSysStockDetailService.queryList(stockDetailQueryBo);
        if (sysStockDetailVos == null && sysStockDetailVos.size() == 0) {
            return Result.err().msg("移出货位无保险杠库存");
        }

        BaseLocation outBaseLocation = iBaseLocationService.getById(outLocationId);
        //查看是否时双深位，如果是则判断单深位是否有库存
        Result<Boolean> booleanResult = checkIsSleep(outBaseLocation);
        if (!Result.isOk(booleanResult)) {
            return booleanResult;
        }
        // 查询移出货位是否有未完成的任务
        LambdaQueryWrapper<BusinDataTask> wrapper = new LambdaQueryWrapper<BusinDataTask>()
                .notIn(BusinDataTask::getTaskStatus, Arrays.asList("2", "3"))
                .in(BusinDataTask::getTaskType, Arrays.asList("9", "16"))
                .eq(BusinDataTask::getFromLayer, outBaseLocation.getLayer())
                .eq(BusinDataTask::getFromColumn, outBaseLocation.getLocationColumn())
                .eq(BusinDataTask::getFromRow, outBaseLocation.getLocationRow()).last("limit 1");
        BusinDataTask businDataTask = getOne(wrapper);
        if (businDataTask != null) {
            return Result.err().msg("移出货位有未完成的货位移动任务，不可重复移动");
        }

        //查询目标货位，并预占
        Long inLocationId = bo.getInLocationId();
        BaseLocation inBaseLocation = iBaseLocationService.getById(inLocationId);
        if (inBaseLocation == null) {
            return Result.err().msg("未获取到移入货位信息");
        }

        if (!inBaseLocation.getLocationStatus().equals("0")) {
            return Result.err().msg("移入货位已被占用：" + inBaseLocation.getLocationCode());
        }

        inBaseLocation.setLocationStatus("4");
        iBaseLocationService.updateById(inBaseLocation);
        //更改货位状态未移库中，此货位不可在出库
        outBaseLocation.setLocationStatus("5");
        iBaseLocationService.updateById(outBaseLocation);

        //生成移库出库任务
        int index = 0;
        List<BusinDataTaskGoods> taskGoodsList = new ArrayList<>();
        List<SysStockDetail> sysStockDetails = new ArrayList<>();


        String inTunnel = inBaseLocation.getTunnel();
        String outTunnel = outBaseLocation.getTunnel();
        BusinDataTask dataTaskAdd = new BusinDataTask();
        BusinDataTask dataTaskOut = new BusinDataTask();
        BusinDataTask dataTaskIn = new BusinDataTask();

        if (!inTunnel.equals(outTunnel)) {
            dataTaskOut.setTaskStatus("0");
            dataTaskOut.setBatch(DateUtils.getDate());
            dataTaskOut.setIsUrgent("0");//非紧急任务
            dataTaskOut.setIsTop("0");
            dataTaskOut.setPriority("0");
            dataTaskOut.setFromColumn(outBaseLocation.getLocationColumn());
            dataTaskOut.setFromLayer(outBaseLocation.getLayer());
            dataTaskOut.setFromRow(outBaseLocation.getLocationRow());
            dataTaskOut.setTaskType(TaskTypeEnum.relocation_out.getValue());

            dataTaskIn.setTaskStatus("0");
            dataTaskIn.setBatch(DateUtils.getDate());
            dataTaskIn.setIsUrgent("0");//非紧急任务
            dataTaskIn.setIsTop("0");
            dataTaskIn.setPriority("0");
            dataTaskIn.setToLayer(inBaseLocation.getLayer());
            dataTaskIn.setToRow(inBaseLocation.getLocationRow());
            dataTaskIn.setToColumn(inBaseLocation.getLocationColumn());
            dataTaskIn.setTaskType(TaskTypeEnum.relocation_in.getValue());

        } else {
            dataTaskAdd.setTaskStatus("0");
            dataTaskAdd.setBatch(DateUtils.getDate());
            dataTaskAdd.setIsUrgent("0");//非紧急任务
            dataTaskAdd.setIsTop("0");
            dataTaskAdd.setPriority("0");
            dataTaskAdd.setToLayer(inBaseLocation.getLayer());
            dataTaskAdd.setToRow(inBaseLocation.getLocationRow());
            dataTaskAdd.setToColumn(inBaseLocation.getLocationColumn());
            dataTaskAdd.setTaskType(TaskTypeEnum.seat_adjustment.getValue());
        }

        for (SysStockDetailVo sysStockDetailVo : sysStockDetailVos) {
            Long taskInId = 0L;
            Long taskOutId = 0L;
            if (index == 0) {
                if (!inTunnel.equals(outTunnel)) {
                    //根据巷道获取目标货位的输送线的agv接驳点
                    BasePointQueryBo pointQueryBo = new BasePointQueryBo();
                    pointQueryBo.setTunnel(inTunnel);
                    pointQueryBo.setGroupNo("4");
                    BasePointVo basePointVo = iBasePointService.selectBasePointByQuery(pointQueryBo);
                    String pointNo = basePointVo.getPointNo();
                    Long plcId = basePointVo.getPlcId();
                    String devCode = basePointVo.getDevCode();
                    dataTaskOut.setIsDown(basePointVo.getIsDown());
                    dataTaskOut.setTaskPath(pointNo);
                    dataTaskOut.setPlcId(plcId);
                    dataTaskOut.setDpsNoOne(Long.valueOf(devCode));
                    dataTaskOut.setLocationId(inLocationId);
                    this.save(dataTaskIn);
                    taskInId = dataTaskIn.getId();
                    dataTaskOut.setAssociatedTasksId(dataTaskIn.getId().toString());
                    this.save(dataTaskOut);
                    taskOutId = dataTaskOut.getId();
                } else {
                    this.save(dataTaskAdd);
                }
                index++;
            }

            //保险杠信息
            if (!inTunnel.equals(outTunnel)) {
                BusinDataTaskGoods taskGoodsIn = new BusinDataTaskGoods();
                taskGoodsIn.setGoodsNo(sysStockDetailVo.getGoodsNo());
                taskGoodsIn.setIsPunching(sysStockDetailVo.getIsPuch());
                taskGoodsIn.setBranchId(SecurityUtils.getCurrentBranchId());
                taskGoodsIn.setTaskCode(taskInId);
                taskGoodsList.add(taskGoodsIn);
                BusinDataTaskGoods taskGoodsOut = new BusinDataTaskGoods();
                taskGoodsOut.setGoodsNo(sysStockDetailVo.getGoodsNo());
                taskGoodsOut.setIsPunching(sysStockDetailVo.getIsPuch());
                taskGoodsOut.setBranchId(SecurityUtils.getCurrentBranchId());
                taskGoodsOut.setTaskCode(taskOutId);
                taskGoodsList.add(taskGoodsOut);
            }

//            //出库预占
//            sysStockDetailVo.setOutQty(sysStockDetailVo.getQty().intValue());
//            SysStockDetail sysStockDetail = BeanUtil.toBean(sysStockDetailVo, SysStockDetail.class);
//            sysStockDetail.setOutTime(DateUtils.getNowDate());
//            sysStockDetails.add(sysStockDetail);
        }


        //    iSysStockDetailService.updateBatchById(sysStockDetails);
        return iBusinDataTaskGoodsService.saveBatch(taskGoodsList) ? Result.ok() : Result.err().msg("移库任务失败");
    }


    public Result<Boolean> checkIsSleep(BaseLocation baseLocationVo) {
        List<SysStockDetailVo> sysStockDetailVoList = null;
        //查询指定出库的货位是不是双深位，如果是，则查询单深位是否有库存
        if (baseLocationVo.getIsDeep().equals("2")) {
            String locationRow = baseLocationVo.getLocationRow();
            String locationColumn = baseLocationVo.getLocationColumn();
            String layer = baseLocationVo.getLayer();
            if (locationRow.equals("1")) {
                locationRow = "2";
            } else if (locationRow.equals("4")) {
                locationRow = "3";
            } else if (locationRow.equals("16")) {
                locationRow = "15";
            }
            BaseLocation one = iBaseLocationService.getOne(new LambdaQueryWrapper<BaseLocation>()
                    .eq(BaseLocation::getLocationRow, locationRow)
                    .eq(BaseLocation::getLocationColumn, locationColumn)
                    .eq(BaseLocation::getLayer, layer));
            Result<List<SysStockDetailVo>> stockListResult = iSysStockDetailService.queryByLocation(one.getId());
            if (Result.isOk(stockListResult)) {
                sysStockDetailVoList = stockListResult.getData();
                if (sysStockDetailVoList != null && sysStockDetailVoList.size() != 0) {
                    return Result.err().msg("指定出库货位是双深位，单深位有货，不可出库" + baseLocationVo.getLocationCode());
                }
            }
        }
        return Result.ok().msg("单深位");
    }
}
