package com.wms_main.service.quartz_job.serviceImpl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.wms_main.app.AppCommon;
import com.wms_main.constant.AppConstant;
import com.wms_main.constant.enums.wms.*;
import com.wms_main.dao.*;
import com.wms_main.model.po.*;
import com.wms_main.repository.utils.StringUtils;
import com.wms_main.repository.utils.UUIDUtils;
import com.wms_main.service.business.IStockDataService;
import com.wms_main.service.quartz_job.IOutsExecutorService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class OutsExecutorServiceImpl implements IOutsExecutorService {
    private final ITAppOutsService appOutsService;// 出库单服务
    private final ITAppStockService appStockService;// 库存服务
    private final ITAppPickTaskService appPickTaskService;// 拣选任务服务
    private final ITAppTaskService appTaskService;// 任务服务
    private final ITAppVehicleService appVehicleService;// 载具服务
    private final ITAppWorkService appWorkService;// 工作服务
    private final ITAppWorkRecordService appWorkRecordService;// 工作记录服务
    private final ITAppStandService appStandService;// 站台服务
    private final ITAppDbsService appDbsService;// dbs服务
    private final ITAppEquipmentService appEquipmentService;// 设备服务
    private final ITAppStandWorkService appStandWorkService;// 站台工作服务
    private final ITAppPickPlanService appPickPlanService;// 拣选计划服务
    private final IStockDataService stockDataService;// 库存数据服务
    private final ITAppOutsRecordService appOutsRecordService;// 出库单记录服务
    private final AppCommon appCommon;// 应用共通数据

    /**
     * 解析出库单 实现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeOuts() {
        try {
            // 查询到对应的出库单
            List<TAppOuts> appOutsList = appOutsService.list(
                    new LambdaQueryWrapper<TAppOuts>().orderByDesc(TAppOuts::getOutType)
            );
            if (appOutsList == null || appOutsList.isEmpty()) {
                return;
            }
            // 需要保存的信息
            List<TAppTask> newOutWmsTasks = new ArrayList<>();// 新的出库任务
            List<TAppPickTask> newPickTasks = new ArrayList<>();// 新的拣选任务
            List<String> thisTimeOutVehicleIds = new ArrayList<>();// 本次出库载具
            List<TAppPickPlan> newPickPlans = new ArrayList<>();// 拣选计划
            // 拣选任务
            List<TAppPickTask> pickTasks = appPickTaskService.list();
            // 查询库存，条件：剩余数量>0，回库中、锁定以外的库存状态。
            List<TAppStock> allStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>()
                    .le(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode())
                    .gt(TAppStock::getRemainNum, 0)
                    .orderByAsc(TAppStock::getFirstInTime));
            List<TAppVehicle> emptyVehicles = appVehicleService.list(new LambdaQueryWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getIsEmpty, 1)
                    .eq(TAppVehicle::getVehicleStatus, WmsVehicleStatusEnums.ON.getCode())
                    .orderByAsc(TAppVehicle::getLastInTime));// 先进先出
            // 获取可用堆垛机
            List<TAppEquipment> usableStackers = appEquipmentService.list(new LambdaQueryWrapper<TAppEquipment>()
                    .eq(TAppEquipment::getEquipmentType, 1)
                    .eq(TAppEquipment::getEquipmentStatus, WmsUsableStatusEnums.USABLE.getCode()));
            Map<Integer, String> equipVehicleMap = new HashMap<>();
            getVehicleEquipMap("", true, equipVehicleMap, usableStackers);
            for (TAppOuts appOuts : appOutsList) {
                if (appOuts.getDistributeNum() >= appOuts.getNeedNum()) {
                    continue;
                }
                // 判断目前是否是空箱任务
                if (Objects.equals(appOuts.getOutType(), WmsOutTypeEnums.EMPTY.getCode())) {
                    solveEmpty(appOuts, emptyVehicles, equipVehicleMap, newOutWmsTasks, thisTimeOutVehicleIds);
                } else if (Objects.equals(appOuts.getOutType(), WmsOutTypeEnums.FOR_IN.getCode())) {
                    solveOutForIn(equipVehicleMap, appOuts, allStocks, pickTasks, newOutWmsTasks, newPickTasks, thisTimeOutVehicleIds);
                } else if (Objects.equals(appOuts.getOutType(), WmsOutTypeEnums.EMERGE.getCode())) {
                    // 紧急出库
                    solveEmerge(equipVehicleMap, appOuts, allStocks, pickTasks, newOutWmsTasks, newPickTasks, thisTimeOutVehicleIds, newPickPlans);
                }
            }
            // 保存出库单
            appOutsService.updateBatchById(appOutsList);
            // 保存出库任务
            if (!newOutWmsTasks.isEmpty()) {
                appTaskService.saveBatch(newOutWmsTasks);
            }
            // 保存拣选任务
            if (!newPickTasks.isEmpty()) {
                appPickTaskService.saveBatch(newPickTasks);
            }
            // 合并拣选计划---箱号+料号+站台+类型+index进行数量叠加
            if (!newPickPlans.isEmpty()) {
                appPickPlanService.saveOrUpdateBatch(mergedPickPlan(newPickPlans));
            }
            // 创建一个只复制剩余数量的库存列表
            List<TAppStock> onlyRemainNumStocks = allStocks.stream().map(stock -> {
                TAppStock stockCopy = new TAppStock();
                stockCopy.setStockId(stock.getStockId());
                stockCopy.setRemainNum(stock.getRemainNum());
                if (!thisTimeOutVehicleIds.isEmpty() && thisTimeOutVehicleIds.contains(stock.getVehicleId())) {
                    stockCopy.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                }
                return stockCopy;
            }).toList();
            // 更新库存信息
            appStockService.updateBatchById(onlyRemainNumStocks);
            // 更新载具信息
            if (!thisTimeOutVehicleIds.isEmpty()) {
                appVehicleService.update(new LambdaUpdateWrapper<TAppVehicle>()
                        .set(TAppVehicle::getVehicleStatus, WmsVehicleStatusEnums.OUT.getCode())
                        .in(TAppVehicle::getVehicleId, thisTimeOutVehicleIds));
            }
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("解析出库单发生异常。{}", StringUtils.objectToString(e));
        }
    }

    /**
     * 处理空载具出库请求
     *
     * @param appOuts               出库请求
     * @param emptyVehicles         所有的空载具
     * @param equipVehicleMap       载具与载具编号的映射
     * @param newOutWmsTasks        新的出库任务
     * @param thisTimeOutVehicleIds 本次出库的载具列表
     */
    private void solveEmpty(TAppOuts appOuts, List<TAppVehicle> emptyVehicles, Map<Integer, String> equipVehicleMap, List<TAppTask> newOutWmsTasks, List<String> thisTimeOutVehicleIds) {
        int needNum = appOuts.getNeedNum() - appOuts.getDistributeNum();
        if (needNum <= 0) {
            return;
        }
        // 生成空箱出库任务
        for (TAppVehicle emptyVehicle : emptyVehicles) {
            if (needNum <= 0) {
                break;
            }
            if (Objects.equals(emptyVehicle.getIsLock(), 1) || !Objects.equals(emptyVehicle.getVehicleStatus(), WmsVehicleStatusEnums.ON.getCode())) {
                continue;
            }
            // 当前库位无法生成空载具出库
            if (ifThisLocationCantOut(emptyVehicle.getLocationId(), equipVehicleMap)) {
                continue;
            }
            // 如果指定了载具号
            if (StringUtils.isNotEmpty(appOuts.getVehicleId()) && !Objects.equals(emptyVehicle.getVehicleId(), appOuts.getVehicleId())) {
                continue;
            }
            // 生成出库任务
            newOutWmsTasks.add(new TAppTask(
                    UUIDUtils.getNewUUID(),
                    WmsTaskTypeEnums.OUT.getCode(),
                    0,
                    1,
                    emptyVehicle.getVehicleId(),
                    emptyVehicle.getLocationId(),
                    null,
                    null,
                    LocalDateTime.now(),
                    null,
                    AppConstant.EMPTY_GOODS_ID,
                    0.0,
                    0.0,
                    appOuts.getUserName(),
                    "",
                    appOuts.getDestination(),
                    "",
                    "",
                    "",
                    "",
                    ""
            ));
            emptyVehicle.setVehicleStatus(WmsVehicleStatusEnums.OUT.getCode());
            thisTimeOutVehicleIds.add(emptyVehicle.getVehicleId());
            updateVehicleEquipMapByLocation(equipVehicleMap, emptyVehicle.getVehicleId(), emptyVehicle.getLocationId());
            needNum--;
        }
        appOuts.setDistributeNum(appOuts.getNeedNum() - needNum);
    }

    /**
     * 处理出库（入库用）请求
     * @param equipVehicleMap 载具与载具编号的映射
     * @param appOuts 出库单
     * @param allStocks 所有库存
     * @param pickTasks 拣选任务
     * @param newOutWmsTasks 新的出库任务
     * @param newPickTasks 新的拣选任务
     * @param thisTimeOutVehicleIds 本次出库的载具列表
     */
    private void solveOutForIn(Map<Integer, String> equipVehicleMap, TAppOuts appOuts, List<TAppStock> allStocks, List<TAppPickTask> pickTasks, List<TAppTask> newOutWmsTasks, List<TAppPickTask> newPickTasks, List<String> thisTimeOutVehicleIds) {
        int needNum = appOuts.getNeedNum() - appOuts.getDistributeNum();
        if (needNum <= 0) {
            return;
        }
        // 根据箱号+料号 map一下数量
        Map<String, Double> goodsNumMap = new HashMap<>();
        for (TAppStock stock : allStocks) {
            String key = stock.getVehicleId() + "_" + stock.getGoodsId();
            if (goodsNumMap.containsKey(key)) {
                goodsNumMap.replace(key, goodsNumMap.get(key) + stock.getRemainNum());
            } else {
                goodsNumMap.put(key, stock.getRemainNum());
            }
        }
        // 是否已经出库了
        boolean alreadyOut = false;
        for (TAppStock stock : allStocks) {
            if (thisTimeOutVehicleIds.contains(stock.getVehicleId())) {
                // 设置这个箱子的库存都为出库中
                stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
            }
            if (alreadyOut) {
                // 已经有了，不需要再生成了
                continue;
            }
            if (!Objects.equals(appOuts.getGoodsId(), stock.getGoodsId())) {
                // 不是这个料
                continue;
            }
            if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode()) && ifThisLocationCantOut(stock.getLocationId(), equipVehicleMap)) {
                // 当前堆垛机已经无法生成新的出库任务了
                continue;
            }
            // 判断这个库存还能不能往里面放料
            TAppGoods appGoods = appCommon.getInstantGoodsByGoodsId(stock.getGoodsId());
            if (appGoods == null) {
                continue;
            }
            String key = stock.getVehicleId() + "_" + stock.getGoodsId();
            Double stockNum = goodsNumMap.getOrDefault(key, Double.valueOf(appGoods.getBoxQty() * appGoods.getMaxBoxNum()));
            // 判断是否还能够入库用
            if (stockNum <= (appGoods.getMaxBoxNum() - 1) * appGoods.getBoxQty()) {
                // 已有的拣选任务
                List<TAppPickTask> oldPickTasks = new ArrayList<>();
                if (pickTasks != null) {
                    oldPickTasks = pickTasks.stream().filter(pickTask ->
                            Objects.equals(pickTask.getPickStand(), appOuts.getDestination())
                                    && pickTask.getVehicleId().equals(stock.getVehicleId())
                                    && Objects.equals(pickTask.getPickStatus(), WmsPickTaskStatusEnum.FOR_IN.getCode())).toList();
                }
                // 新生成的拣选任务
                List<TAppPickTask> newOldPickTasks = newPickTasks.stream().filter(pickTask -> pickTask.getVehicleId().equals(stock.getVehicleId())
                        && Objects.equals(pickTask.getPickStand(), appOuts.getDestination())
                        && Objects.equals(pickTask.getPickStatus(), WmsPickTaskStatusEnum.FOR_IN.getCode())).toList();
                // 生成拣选任务
                if (oldPickTasks.isEmpty() && newOldPickTasks.isEmpty()) {
                    newPickTasks.add(new TAppPickTask(
                            UUIDUtils.getNewUUID(),
                            appOuts.getDestination(),
                            stock.getVehicleId(),
                            WmsPickTaskStatusEnum.FOR_IN.getCode(),
                            LocalDateTime.now(),
                            null, null, null
                    ));
                }
                if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode())) {
                    // 需要生成出库任务
                    newOutWmsTasks.add(new TAppTask(
                            UUIDUtils.getNewUUID(),
                            WmsTaskTypeEnums.OUT.getCode(),
                            0,
                            1,
                            stock.getVehicleId(),
                            stock.getLocationId(),
                            null,
                            null,
                            LocalDateTime.now(),
                            null,
                            AppConstant.EMPTY_GOODS_ID,
                            0.0,
                            0.0,
                            appOuts.getUserName(),
                            "",
                            appOuts.getDestination(),
                            "",
                            "",
                            "",
                            "",
                            ""
                    ));
                    stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                    thisTimeOutVehicleIds.add(stock.getVehicleId());
                    updateVehicleEquipMapByLocation(equipVehicleMap, stock.getVehicleId(), stock.getLocationId());
                }
                // 这个料已经生成了一个出库的。
                alreadyOut = true;
                appOuts.setDistributeNum(1);
            }
        }
    }

    /**
     * 处理紧急出库任务
     *
     * @param equipVehicleMap       堆垛机与载具的映射
     * @param appOuts               出库单
     * @param allStocks             所有库存
     * @param pickTasks             所有拣选任务
     * @param newOutWmsTasks        新的出库任务
     * @param newPickTasks          新的拣选任务
     * @param thisTimeOutVehicleIds 本次出库载具
     * @param newPickPlans          新的拣选计划
     */
    private void solveEmerge(Map<Integer, String> equipVehicleMap, TAppOuts appOuts, List<TAppStock> allStocks, List<TAppPickTask> pickTasks, List<TAppTask> newOutWmsTasks, List<TAppPickTask> newPickTasks, List<String> thisTimeOutVehicleIds, List<TAppPickPlan> newPickPlans) {
        // 查找
        for (TAppStock stock : allStocks) {
            if (thisTimeOutVehicleIds.contains(stock.getVehicleId())) {
                // 设置这个箱子的库存都为出库中
                stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
            }
            if (!Objects.equals(appOuts.getGoodsId(), stock.getGoodsId())) {
                // 不是这个料
                continue;
            }
//            if (StringUtils.isNotEmpty(appOuts.getVehicleId()) && !Objects.equals(stock.getVehicleId(), appOuts.getVehicleId())) {
//                // 紧急出库选择了箱号
//                continue;
//            }
            String stockId = stockDataService.getFirstInStock(stock.getGoodsId(), allStocks);
            if (StringUtils.isNotEmpty(stockId) && !Objects.equals(stockId, stock.getStockId())) {
                // 不是当前物料最先进的库存
                continue;
            }
            if (stock.getRemainNum() <= 0) {
                // 数量不够
                continue;
            }
            if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode()) && ifThisLocationCantOut(stock.getLocationId(), equipVehicleMap)) {
                // 当前堆垛机已经无法生成新的出库任务了
                continue;
            }
            // 判断当前的这条库存，当前站台是否需要
            Double originNum = stock.getRemainNum();
            Double remainNum = stock.getRemainNum();
            int needNum = appOuts.getNeedNum() - appOuts.getDistributeNum();
            if (needNum < remainNum) {
                appOuts.setDistributeNum(appOuts.getNeedNum());
                remainNum = remainNum - needNum;
            } else {
                appOuts.setDistributeNum((int) (appOuts.getDistributeNum() + remainNum));
                remainNum = 0.0;
            }
            if (remainNum == originNum) {
                // 没用到这条库存
                continue;
            }
            // 生成拣选计划
            TAppPickPlan pickPlan = new TAppPickPlan(
                    UUIDUtils.getNewUUID(),
                    stock.getVehicleId(),
                    stock.getGoodsId(),
                    originNum - remainNum,
                    2,
                    appOuts.getTaskId(),
                    appOuts.getDestination()
            );
            newPickPlans.add(pickPlan);
            // 库存变动了，需要更新库存信息
            stock.setRemainNum(remainNum);
            // 拣选任务状态
            int pickTaskStatus = WmsPickTaskStatusEnum.TEMP.getCode();
            // 库存正常
            if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode())) {
                // 需要生成出库任务
                newOutWmsTasks.add(new TAppTask(
                        UUIDUtils.getNewUUID(),
                        WmsTaskTypeEnums.OUT.getCode(),
                        0,
                        9,
                        stock.getVehicleId(),
                        stock.getLocationId(),
                        null,
                        null,
                        LocalDateTime.now(),
                        null,
                        AppConstant.EMPTY_GOODS_ID,
                        0.0,
                        0.0,
                        appOuts.getUserName(),
                        "",
                        appOuts.getDestination(),
                        "",
                        "",
                        "",
                        "",
                        ""
                ));
                stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                thisTimeOutVehicleIds.add(stock.getVehicleId());
                updateVehicleEquipMapByLocation(equipVehicleMap, stock.getVehicleId(), stock.getLocationId());
            }
            // 如果是已经出库的库存
            if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OUTED.getCode())) {
                pickTaskStatus = WmsPickTaskStatusEnum.WAIT.getCode();
            }
            // 已有的拣选任务
            List<TAppPickTask> oldPickTasks = new ArrayList<>();
            if (pickTasks != null) {
                oldPickTasks = pickTasks.stream().filter(pickTask ->
                        Objects.equals(pickTask.getPickStand(), appOuts.getDestination())
                                && pickTask.getVehicleId().equals(stock.getVehicleId())
                && !Objects.equals(pickTask.getPickStatus(), WmsPickTaskStatusEnum.FOR_IN.getCode())).toList();
            }
            // 新生成的拣选任务
            List<TAppPickTask> newOldPickTasks = newPickTasks.stream().filter(pickTask -> pickTask.getVehicleId().equals(stock.getVehicleId())
                    && Objects.equals(pickTask.getPickStand(), appOuts.getDestination())
            && !Objects.equals(pickTask.getPickStatus(), WmsPickTaskStatusEnum.FOR_IN.getCode())).toList();
            // 生成拣选任务
            if (oldPickTasks.isEmpty() && newOldPickTasks.isEmpty()) {
                newPickTasks.add(new TAppPickTask(
                        UUIDUtils.getNewUUID(),
                        appOuts.getDestination(),
                        stock.getVehicleId(),
                        pickTaskStatus,
                        LocalDateTime.now(),
                        null, null, null
                ));
            }
        }
    }

    /**
     * 解析工作
     * 实现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void executeKateWorks() {
        try {
            // 查询所有的未完成的工作
            List<TAppWork> allWorks = appWorkService.list(new LambdaQueryWrapper<TAppWork>()
                    .notIn(TAppWork::getWorkStatus, -1, 2)
                    .ne(TAppWork::getIsOut, 1)
                    .apply("distribute_num < need_num"));
            if (allWorks == null || allWorks.isEmpty()) {
                // 没有未完成的工作
                return;
            }
            // 获取站台容量配置
            int standCapacity = 8;
            try {
                standCapacity = Integer.parseInt(appCommon.getConfigByKey(AppConfigKeyEnums.STAND_CAPACITY.getKey()));
            } catch (Exception e) {
                log.warn("获取站台容量失败，使用默认配置。");
            }
            // 查找到所有的可用的拣选站台
            List<TAppStand> standList = appStandService.list(new LambdaQueryWrapper<TAppStand>()
                    .eq(TAppStand::getStandType, 1));
            if (standList == null || standList.isEmpty()) {
                log.error("没有配置拣选站台，请添加站台数据。");
                return;
            }
            // 可用站台号列表
            List<String> usableStandIds = standList.stream().filter(stand -> stand.getStandStatus() == WmsUsableStatusEnums.USABLE.getCode()).map(TAppStand::getStandId).toList();
            if (usableStandIds.isEmpty()) {
                log.error("没有可用站台。");
                return;
            }
            // 获取可用堆垛机
            List<TAppEquipment> usableStackers = appEquipmentService.list(new LambdaQueryWrapper<TAppEquipment>()
                    .eq(TAppEquipment::getEquipmentType, 1)
                    .eq(TAppEquipment::getEquipmentStatus, WmsUsableStatusEnums.USABLE.getCode()));
            // 查询库存，条件：剩余数量>0，回库中、锁定以外的库存状态。
            List<TAppStock> allStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>()
                    .le(TAppStock::getStockStatus, WmsStockStatusEnums.OUTED.getCode())
                    .gt(TAppStock::getRemainNum, 0)
                    .orderByAsc(TAppStock::getFirstInTime));
            if (allStocks == null || allStocks.isEmpty()) {
                log.error("没有库存。");
                return;
            }
            // 需要保存的信息
            List<TAppTask> newOutWmsTasks = new ArrayList<>();
            List<TAppPickTask> newPickTasks = new ArrayList<>();
            List<String> thisTimeOutVehicleIds = new ArrayList<>();
            List<TAppPickPlan> newPickPlans = new ArrayList<>();// 拣选计划
            for (TAppStand stand : standList) {
                // 查询这个站台正在拣配的工作组合（除物料外）
                List<TAppStandWork> currentStandWorks = appStandWorkService.list(new LambdaQueryWrapper<TAppStandWork>()
                        .eq(TAppStandWork::getStandId, stand.getStandId()));
                if (currentStandWorks == null || currentStandWorks.isEmpty()) {
                    // 没有显示当前的拣选工作，跳过
                    continue;
                }
                // 找到这个站台剩余工作中未完成且已分配数量小于需求数量的工作
                List<TAppWork> works = allWorks.stream().filter(work -> {
                    boolean result = work.getWorkStand().equals(stand.getStandId());
                    if (StringUtils.isNotEmpty(currentStandWorks.getFirst().getWorkOrder())) {
                        result = result && Objects.equals(work.getWorkOrder(), currentStandWorks.getFirst().getWorkOrder());
                    }
                    if (StringUtils.isNotEmpty(currentStandWorks.getFirst().getProductId())) {
                        result = result && Objects.equals(work.getProductId(), currentStandWorks.getFirst().getProductId());
                    }
                    if (StringUtils.isNotEmpty(currentStandWorks.getFirst().getSingleProductId())) {
                        result = result && Objects.equals(work.getSingleProductId(), currentStandWorks.getFirst().getSingleProductId());
                    }
                    if (StringUtils.isNotEmpty(currentStandWorks.getFirst().getBoxNo())) {
                        result = result && Objects.equals(work.getBoxNo(), currentStandWorks.getFirst().getBoxNo());
                    }
                    return result;
                }).toList();
                if (works.isEmpty()) {
                    // 这个站台没有工作
                    continue;
                }
                if (stand.getStandStatus() != WmsUsableStatusEnums.USABLE.getCode()) {
                    log.warn("{}不可用，跳过任务生成。", stand.getStandName());
                    continue;
                }
                // 获取这个站台拣选任务
                List<TAppPickTask> thisStandPickTasks = appPickTaskService.list(new LambdaQueryWrapper<TAppPickTask>()
                        .eq(TAppPickTask::getPickStand, stand.getStandId())
                        .ne(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.FOR_IN.getCode()));
                // 数量太多，不允许下发。
                boolean allowNewVehicle = thisStandPickTasks == null || thisStandPickTasks.size() < standCapacity;
                // 判断这个站台有没有紧急出库的任务未完成
                List<TAppOuts> thisStandEmergencyOuts = appOutsService.list(new LambdaQueryWrapper<TAppOuts>()
                        .eq(TAppOuts::getOutType, WmsOutTypeEnums.EMERGE.getCode())
                        .eq(TAppOuts::getDestination, stand.getStandId())
                        .apply("pick_num < need_num"));
                if (!thisStandEmergencyOuts.isEmpty()) {
                    allowNewVehicle = false;
                }
                // 获得可用堆垛机
                Map<Integer, String> equipVehicleMap = new HashMap<>();
                getVehicleEquipMap(stand.getStandId(), allowNewVehicle, equipVehicleMap, usableStackers);
                for (TAppStock stock : allStocks) {
                    if (thisTimeOutVehicleIds.contains(stock.getVehicleId())) {
                        // 设置这个箱子的库存都为出库中
                        stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                    }
                    String stockId = stockDataService.getFirstInStock(stock.getGoodsId(), allStocks);
                    if (StringUtils.isNotEmpty(stockId) && !Objects.equals(stockId, stock.getStockId())) {
                        // 不是当前物料最先进的库存
                        continue;
                    }
                    // 库存没法分配了
                    if (stock.getRemainNum() <= 0) {
                        continue;
                    }
                    if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode()) && ifThisLocationCantOut(stock.getLocationId(), equipVehicleMap)) {
                        // 当前堆垛机已经无法生成新的出库任务了
                        continue;
                    }
                    // 判断当前的这条库存，当前站台是否需要
                    Double originRemainNum = stock.getRemainNum();
                    Double remainNum = stock.getRemainNum();
                    for (TAppWork thisWork : works) {
                        if (!Objects.equals(thisWork.getGoodsId(), stock.getGoodsId())) {
                            // 不是这个料
                            continue;
                        }
                        if (remainNum == 0) {
                            break;
                        }
                        // 需求数量
                        Double remainNeedNum = (double) (thisWork.getNeedNum() - thisWork.getDistributeNum());
                        if (remainNeedNum <= 0) {
                            // 不需要分配
                            continue;
                        }
                        Double thisTimePickNum;
                        if (remainNeedNum < remainNum) {
                            thisTimePickNum = remainNeedNum;
                            thisWork.setDistributeNum(thisWork.getNeedNum());
                            remainNum = remainNum - thisTimePickNum;
                        } else {
                            thisTimePickNum = remainNum;
                            thisWork.setDistributeNum((int) (thisWork.getDistributeNum() + thisTimePickNum));
                            remainNum = 0.0;
                        }
                        thisWork.setWorkStatus(1);// 正在做
                        // 生成拣选计划
                        TAppPickPlan pickPlan = new TAppPickPlan(
                                UUIDUtils.getNewUUID(),
                                stock.getVehicleId(),
                                stock.getGoodsId(),
                                thisTimePickNum,
                                1,
                                thisWork.getWorkIndex(),
                                stand.getStandId()
                        );
                        newPickPlans.add(pickPlan);
                    }
                    if (remainNum == originRemainNum) {
                        // 没用到这条库存
                        continue;
                    }
                    // 库存变动了，需要更新库存信息
                    stock.setRemainNum(remainNum);
                    // 拣选任务状态
                    int pickTaskStatus = WmsPickTaskStatusEnum.TEMP.getCode();
                    // 库存正常
                    if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OK.getCode())) {
                        // 需要生成出库任务
                        newOutWmsTasks.add(new TAppTask(
                                UUIDUtils.getNewUUID(),
                                WmsTaskTypeEnums.OUT.getCode(),
                                0,
                                1,
                                stock.getVehicleId(),
                                stock.getLocationId(),
                                null,
                                null,
                                LocalDateTime.now(),
                                null,
                                AppConstant.EMPTY_GOODS_ID,
                                0.0,
                                0.0,
                                "wms_auto",
                                "",
                                stand.getStandId(),
                                "",
                                "",
                                "",
                                "",
                                ""
                        ));
                        // 更新信息
                        updateVehicleEquipMapByLocation(equipVehicleMap, stock.getVehicleId(), stock.getLocationId());
                        thisTimeOutVehicleIds.add(stock.getVehicleId());
                        stock.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                    }
                    // 如果是已经出库的库存
                    if (Objects.equals(stock.getStockStatus(), WmsStockStatusEnums.OUTED.getCode())) {
                        pickTaskStatus = WmsPickTaskStatusEnum.WAIT.getCode();
                    }
                    // 已有的拣选任务
                    List<TAppPickTask> oldPickTasks = new ArrayList<>();
                    if (thisStandPickTasks != null) {
                        oldPickTasks = thisStandPickTasks.stream().filter(pickTask -> pickTask.getVehicleId().equals(stock.getVehicleId())).toList();
                    }
                    // 新生成的拣选任务
                    List<TAppPickTask> newOldPickTasks = newPickTasks.stream().filter(pickTask -> pickTask.getVehicleId().equals(stock.getVehicleId())
                            && Objects.equals(pickTask.getPickStand(), stand.getStandId())).toList();
                    // 生成拣选任务
                    if (oldPickTasks.isEmpty() && newOldPickTasks.isEmpty()) {
                        newPickTasks.add(new TAppPickTask(
                                UUIDUtils.getNewUUID(),
                                stand.getStandId(),
                                stock.getVehicleId(),
                                pickTaskStatus,
                                LocalDateTime.now(),
                                null, null, null
                        ));
                    }
                }
                // 更新工作状态
                appWorkService.updateBatchById(works);
            }
            // 保存出库任务
            if (!newOutWmsTasks.isEmpty()) {
                appTaskService.saveBatch(newOutWmsTasks);
            }
            // 保存拣选任务
            if (!newPickTasks.isEmpty()) {
                appPickTaskService.saveBatch(newPickTasks);
            }
            // 合并拣选计划---箱号+料号+站台+类型+index进行数量叠加
            if (!newPickPlans.isEmpty()) {
                appPickPlanService.saveOrUpdateBatch(mergedPickPlan(newPickPlans));
            }
            // 创建一个只复制剩余数量的库存列表
            List<TAppStock> onlyRemainNumStocks = allStocks.stream().map(stock -> {
                TAppStock stockCopy = new TAppStock();
                stockCopy.setStockId(stock.getStockId());
                stockCopy.setRemainNum(stock.getRemainNum());
                if (!thisTimeOutVehicleIds.isEmpty() && thisTimeOutVehicleIds.contains(stock.getVehicleId())) {
                    stockCopy.setStockStatus(WmsStockStatusEnums.OUTING.getCode());
                }
                return stockCopy;
            }).toList();
            // 更新库存信息
            appStockService.updateBatchById(onlyRemainNumStocks);
            // 更新载具信息
            if (!thisTimeOutVehicleIds.isEmpty()) {
                appVehicleService.update(new LambdaUpdateWrapper<TAppVehicle>()
                        .set(TAppVehicle::getVehicleStatus, WmsVehicleStatusEnums.OUT.getCode())
                        .in(TAppVehicle::getVehicleId, thisTimeOutVehicleIds));
            }
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("解析工作发生异常。{}", StringUtils.objectToString(e));
        }
    }

    /**
     * 修复工作
     * 实现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repairKateWorks() {
        try {
            // 查找非暂存的工作
            List<TAppWork> allWorks = appWorkService.list();
            if (allWorks == null || allWorks.isEmpty()) {
                return;
            }
            // 查询出库的库存
            List<TAppStock> allStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>().orderByAsc(TAppStock::getFirstInTime));
            // 查询所有的拣选任务
            List<TAppPickTask> allPickTasks = appPickTaskService.list(new LambdaQueryWrapper<TAppPickTask>()
                    .ne(TAppPickTask::getPickStatus, WmsPickTaskStatusEnum.FOR_IN.getCode()));
            // 根据工单map一下
            Map<String, List<TAppWork>> worksMap = allWorks.stream().collect(Collectors.groupingBy(TAppWork::getWorkOrder));
            for (String workOrder : worksMap.keySet()) {
                // 工作列表
                List<TAppWork> works = worksMap.get(workOrder);
                // 当前工单是否全部完成
                boolean ifAllFinished = true;
                // 工作记录
                List<TAppWorkRecord> workRecords = new ArrayList<>();
                for (TAppWork work : works) {
                    if (work.getWorkStatus() == -1) {
                        // 暂存工作，不算完成
                        ifAllFinished = false;
                        continue;
                    }
                    if (work.getFinishNum() >= work.getNeedNum()) {
                        // 已经拣选完成的改成完成状态
                        if (work.getWorkStatus() != 2) {
                            work.setWorkStatus(2);
                            work.setLackStatus(0);
                        }
                        // 添加记录
                        workRecords.add(RecordOfWork(work));
                        continue;
                    }
                    // 判断库内料分配的数量是否需要修正
                    if (work.getIsOut() != 1) {
                        List<TAppStock> thisGoodsOutStocks = allStocks.stream().filter(stock -> stock.getGoodsId().equals(work.getGoodsId())).toList();
                        if (thisGoodsOutStocks.isEmpty()) {
                            // 缺料
                            work.setWorkStatus(2);
                            work.setLackStatus(1);
                            work.setFinishTime(LocalDateTime.now());
                            // 缺料不能关闭订单
                            ifAllFinished = false;
                            continue;
                        } else {
                            // 没有出库中或者已出库的则修正已分配数量
                            List<TAppStock> outStocks = thisGoodsOutStocks.stream().filter(stock -> {
                                boolean result = stock.getStockStatus().equals(WmsStockStatusEnums.OUTING.getCode())
                                        || stock.getStockStatus().equals(WmsStockStatusEnums.OUTED.getCode());
                                return result && stock.getGoodsId().equals(work.getGoodsId());
                            }).toList();
                            if (outStocks.isEmpty()) {
                                work.setWorkStatus(1);
                                work.setDistributeNum(work.getFinishNum());
                                ifAllFinished = false;
                                continue;
                            } else {
                                List<String> vehicleIds = outStocks.stream().map(TAppStock::getVehicleId).distinct().toList();
                                // 查询这些载具到这个站台的拣选任务
                                List<TAppPickTask> pickTasks = allPickTasks.stream().filter(pickTask ->
                                        vehicleIds.contains(pickTask.getVehicleId()) && Objects.equals(pickTask.getPickStand(), work.getWorkStand())).toList();
                                if (pickTasks.isEmpty()) {
                                    work.setWorkStatus(1);
                                    work.setDistributeNum(work.getFinishNum());
                                    ifAllFinished = false;
                                    continue;
                                }
                            }
                        }
                    }
                    if (work.getWorkStatus() == 2) {
                        // 未完成的状态要改为未完成
                        work.setWorkStatus(1);
                    }
                    ifAllFinished = false;
                }

                if (ifAllFinished) {
                    // 添加记录
                    appWorkRecordService.saveBatch(workRecords);
                    // 移除
                    appWorkService.removeBatchByIds(works);
                    // 将当前工单设置为完成状态
                    appDbsService.update(new LambdaUpdateWrapper<TAppDbs>()
                            .set(TAppDbs::getDbsStatus, 2)
                            .set(TAppDbs::getFinishTime, LocalDateTime.now())
                            .set(TAppDbs::getRealWorkDate, LocalDate.now())
                            .eq(TAppDbs::getWorkOrder, workOrder));
                } else {
                    // 更新工作
                    appWorkService.updateBatchById(works);
                }
            }
        } catch (Exception e) {
            // 回滚事务
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            log.error("自动修复工作异常。{}", StringUtils.objectToString(e));
        }
    }

    /**
     * 修复站台工作--实现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repairStandWorks()  {
        // 查找到所有的可用的拣选站台
        List<TAppStand> standList = appStandService.list(new LambdaQueryWrapper<TAppStand>()
                .eq(TAppStand::getStandType, 1)
                .eq(TAppStand::getStandStatus, WmsUsableStatusEnums.USABLE.getCode()));
        if (standList == null || standList.isEmpty()) {
            log.error("没有可用的站台，跳过。");
            return;
        }
        // 可用站台号列表
        List<String> usableStandIds = standList.stream().map(TAppStand::getStandId).distinct().toList();
        for (String usableStandId : usableStandIds) {
            try {
                repairStandWork(usableStandId);
            } catch (Exception e) {
                // 回滚事务
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.error("构建站台工作（StandWork）失败。");
            }
        }
    }

    /**
     * 修复出库单--实现
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void repairOuts() {
        List<TAppOuts> allOuts = appOutsService.list();
        List<String> needRemoveOutIds = new ArrayList<>();
        List<TAppOutsRecord> needAddOutRecords = new ArrayList<>();
        // 所有的空箱出库请求
        List<TAppOuts> emptyOuts = allOuts.stream().filter(appOuts -> appOuts.getOutType().equals(WmsOutTypeEnums.EMPTY.getCode())).toList();
        for (TAppOuts emptyOut : emptyOuts) {
            int needNum = emptyOut.getNeedNum() - emptyOut.getDistributeNum();
            if (needNum <= 0) {
                addRemovingOutsAndRecord(needRemoveOutIds, emptyOut, needAddOutRecords);
                continue;
            }
            // 判断数量够不够
            LambdaQueryWrapper<TAppVehicle> queryWrapper = new LambdaQueryWrapper<TAppVehicle>()
                    .eq(TAppVehicle::getVehicleStatus, WmsVehicleStatusEnums.ON.getCode())
                    .eq(TAppVehicle::getIsEmpty, 1);
            // 空箱出库判断能否实现
            if (StringUtils.isNotEmpty(emptyOut.getVehicleId())) {
                queryWrapper.eq(TAppVehicle::getVehicleId, emptyOut.getVehicleId());
            }
            if (appVehicleService.count(queryWrapper) < needNum) {
                // 空箱数量不够了
                addRemovingOutsAndRecord(needRemoveOutIds, emptyOut, needAddOutRecords);
            }
        }
        // 所有的入库用出库请求
        List<TAppOuts> inOuts = allOuts.stream().filter(appOuts -> appOuts.getOutType().equals(WmsOutTypeEnums.FOR_IN.getCode())).toList();
        //     筛选出料号
        List<String> distinctGoodsIdList = inOuts.stream().map(TAppOuts::getGoodsId).distinct().toList();
        //     获取数据map
        Map<String, Map<String, Double>> goodsQtyMap = stockDataService.getCanPutGoodsMap(distinctGoodsIdList);
        for (TAppOuts inOut : inOuts) {
            int needNum = inOut.getNeedNum() - inOut.getDistributeNum();
            if (needNum <= 0) {
                addRemovingOutsAndRecord(needRemoveOutIds, inOut, needAddOutRecords);
                continue;
            }
            if (!goodsQtyMap.containsKey(inOut.getGoodsId())) {
                addRemovingOutsAndRecord(needRemoveOutIds, inOut, needAddOutRecords);
                continue;
            }
            // 判断数量够不够
            Map<String, Double> goodsQtyMapByGoodsId = goodsQtyMap.get(inOut.getGoodsId());
            if (goodsQtyMapByGoodsId.isEmpty()) {
                goodsQtyMap.remove(inOut.getGoodsId());
                addRemovingOutsAndRecord(needRemoveOutIds, inOut, needAddOutRecords);
                continue;
            }
            // 移除一个可用项
            List<String> vehicleIdsOfThisGoods = new ArrayList<>(goodsQtyMapByGoodsId.keySet());
            for (String vehicleId : vehicleIdsOfThisGoods) {
                goodsQtyMapByGoodsId.remove(vehicleId);
                if (goodsQtyMapByGoodsId.isEmpty()) {
                    goodsQtyMap.remove(inOut.getGoodsId());
                }
                break;
            }
        }
        // 所有的紧急出库请求
        List<TAppOuts> emergeOuts = allOuts.stream().filter(appOuts -> appOuts.getOutType().equals(WmsOutTypeEnums.EMERGE.getCode())).toList();
        List<String> emergeGoodsIds = emergeOuts.stream().map(TAppOuts::getGoodsId).distinct().toList();
        if (!emergeGoodsIds.isEmpty()) {
            List<TAppStock> emergeStocks = appStockService.list(new LambdaQueryWrapper<TAppStock>()
                    .in(TAppStock::getGoodsId, emergeGoodsIds));
            for (TAppOuts emergeOut : emergeOuts) {
                List<TAppStock> emergeStocksOfThisGoodsId = emergeStocks.stream().filter(stock -> stock.getGoodsId().equals(emergeOut.getGoodsId())).toList();
                if (emergeStocksOfThisGoodsId.isEmpty()) {
                    addRemovingOutsAndRecord(needRemoveOutIds, emergeOut, needAddOutRecords);
                }
            }
        }
        // 移除任务
        if (!needRemoveOutIds.isEmpty()) {
            appOutsService.removeBatchByIds(needRemoveOutIds);
        }
        // 添加任务记录
        if (!needAddOutRecords.isEmpty()) {
            appOutsRecordService.saveBatch(needAddOutRecords);
        }
    }

    /**
     * 转化记录
     *
     * @param appWork 记录
     * @return 转化后的记录
     */
    private TAppWorkRecord RecordOfWork(TAppWork appWork) {
        return new TAppWorkRecord(
                appWork.getWorkIndex(),
                appWork.getWorkOrder(),
                appWork.getPlanStartDate(),
                appWork.getProductId(),
                appWork.getSingleProductId(),
                appWork.getBoxNo(),
                appWork.getGoodsId(),
                appWork.getNeedNum(),
                appWork.getFinishNum(),
                appWork.getWorkStand(),
                appWork.getWorkStatus(),
                appWork.getWorkUser(),
                appWork.getCreateTime(),
                appWork.getFinishTime(),
                appWork.getLackStatus(),
                appWork.getIsOut()
        );
    }

    /**
     * 构建站台工作StandWork
     *
     * @param standId 站台号
     */
    private void repairStandWork(String standId) {
        List<TAppWork> allWorks = appWorkService.list(new LambdaQueryWrapper<TAppWork>()
                .eq(TAppWork::getWorkStand, standId));
        if (allWorks == null || allWorks.isEmpty()) {
            return;
        }
        // 查询到当前站台的工作
        List<TAppStandWork> standWorks = appStandWorkService.list(new LambdaQueryWrapper<TAppStandWork>()
                .eq(TAppStandWork::getStandId, standId));
        if (standWorks == null || standWorks.isEmpty()) {
            // 构建新的StandWork
            genNewStandWork(standId, allWorks);
        } else {
            // 判断当前选项的工作是否已经全部完成
            TAppStandWork currentStandWork = standWorks.getFirst();
            // 移除旧的并添加新的
            removeOldStandWork(standId, currentStandWork, allWorks);
        }
    }

    /**
     * 创建一个新的StandWork
     *
     * @param standId  站台号
     * @param allWorks 当前站台所有工作
     */
    private void genNewStandWork(String standId, List<TAppWork> allWorks) {
        // 判断这个站台是否还有其他未完成的工作
        List<TAppWork> works = allWorks.stream().filter(work -> !List.of(-1, 2).contains(work.getWorkStatus())).toList();
        if (works.isEmpty()) {
            // 这个站台没有未完成的工作了
            return;
        }
        TAppWork targetWork = null;
        // 进行中的工作
        List<TAppWork> doingWorks = works.stream().filter(work -> work.getWorkStatus() == 1).toList();
        // 未开始的工作
        List<TAppWork> waitWorks = works.stream().filter(work -> work.getWorkStatus() == 0).toList();
        if (!doingWorks.isEmpty()) {
            targetWork = doingWorks.getFirst();
        } else if (!waitWorks.isEmpty()) {
            targetWork = waitWorks.getFirst();
        }
        // 没有工作
        if (targetWork == null) {
            return;
        }
        // 添加standWork
        TAppStandWork standWork = new TAppStandWork();
        standWork.setWorkId(UUIDUtils.getNewUUID());
        standWork.setStandId(standId);
        standWork.setWorkOrder(targetWork.getWorkOrder());
        standWork.setProductId(targetWork.getProductId());
        if (StringUtils.isNotEmpty(targetWork.getSingleProductId())) {
            standWork.setSingleProductId(targetWork.getSingleProductId());
        }
        standWork.setBoxNo(targetWork.getBoxNo());
        appStandWorkService.save(standWork);
    }

    /**
     * 移除过期的StandWork并添加新的
     *
     * @param standId          站台号
     * @param currentStandWork 现有的StandWork
     * @param allWorks         当前站台所有工作
     */
    private void removeOldStandWork(String standId, TAppStandWork currentStandWork, List<TAppWork> allWorks) {
        boolean genNewStandWork = false;
        if (currentStandWork == null || StringUtils.isEmpty(currentStandWork.getWorkOrder())) {
            return;
        }
        List<TAppWork> filterWorks = allWorks.stream().filter(work -> {
            boolean result = Objects.equals(work.getWorkOrder(), currentStandWork.getWorkOrder())
                    && Objects.equals(work.getProductId(), currentStandWork.getProductId())
                    && Objects.equals(work.getBoxNo(), currentStandWork.getBoxNo());
            if (StringUtils.isNotEmpty(currentStandWork.getSingleProductId())) {
                result = result && Objects.equals(work.getSingleProductId(), currentStandWork.getSingleProductId());
            }
            return result;
        }).toList();
        if (!filterWorks.isEmpty()) {
            // 判断当前的工作中有没有未完成的
            List<TAppWork> notFinishedWorks = filterWorks.stream().filter(work -> !List.of(-1, 2).contains(work.getWorkStatus())).toList();
            if (notFinishedWorks.isEmpty()) {
                // 当前站台工作全部完成---移除当前的，并增加新的
                genNewStandWork = true;
            }
        } else {
            genNewStandWork = true;
        }
        if (genNewStandWork) {
            appStandWorkService.remove(new LambdaQueryWrapper<TAppStandWork>().eq(TAppStandWork::getStandId, standId));
            genNewStandWork(standId, allWorks);
        }
    }

    /**
     * 生成设备载具map
     *
     * @param standId         站台号
     * @param allowNewVehicle 是否允许新箱出库
     * @param equipVehicleMap 设备载具map
     * @param usableStackers  可用堆垛机
     */
    private void getVehicleEquipMap(String standId, boolean allowNewVehicle, Map<Integer, String> equipVehicleMap, List<TAppEquipment> usableStackers) {
        if (allowNewVehicle && !usableStackers.isEmpty()) {
            usableStackers.forEach(equipment -> {
                if (equipVehicleMap.containsKey(equipment.getEquipmentId())) {
                    return;
                }
                equipVehicleMap.put(equipment.getEquipmentId(), "");
            });
        }
        // 获取这个站台请求过的出库任务
        List<TAppTask> outTaskList = appTaskService.list(new LambdaQueryWrapper<TAppTask>()
                .eq(TAppTask::getTaskType, WmsTaskTypeEnums.OUT.getCode())
                .eq(StringUtils.isNotEmpty(standId), TAppTask::getCallStand, standId));
        if (outTaskList != null && !outTaskList.isEmpty()) {
            // 当这个设备存在出库任务时，更新设备载具map
            for (TAppTask outTask : outTaskList) {
                TAppLocation originLocation = appCommon.getInstantLocationByLocationId(outTask.getOrigin());
                if (originLocation != null && equipVehicleMap.containsKey(originLocation.getEquipmentId())) {
                    equipVehicleMap.replace(originLocation.getEquipmentId(), outTask.getVehicleId());
                }
            }
        }
    }

    /**
     * 合并拣选计划列表
     *
     * @param beforeMergePickPlanList 合并前的列表
     * @return 合并后的列表
     */
    private List<TAppPickPlan> mergedPickPlan(List<TAppPickPlan> beforeMergePickPlanList) {
        Map<String, TAppPickPlan> mergedPickPlanMap = new HashMap<>();
        // 查询出目前已经存在的pickPlan
        List<TAppPickPlan> existPickPlanList = appPickPlanService.list();
        // 循环merge
        for (TAppPickPlan beforeMergePickPlan : beforeMergePickPlanList) {
            // key：站台+箱号+料号+拣选类型+index
            String key = beforeMergePickPlan.getStandId() + "_"
                    + beforeMergePickPlan.getVehicleId() + "_"
                    + beforeMergePickPlan.getGoodsId() + "_"
                    + beforeMergePickPlan.getPickType() + "_"
                    + beforeMergePickPlan.getWorkIndex();
            if (mergedPickPlanMap.containsKey(key)) {
                // 之前已经合并过
                TAppPickPlan mergedPickPlan = mergedPickPlanMap.get(key);
                mergedPickPlan.setPlanPickQty(mergedPickPlan.getPlanPickQty() + beforeMergePickPlan.getPlanPickQty());
                mergedPickPlanMap.replace(key, mergedPickPlan);
            } else {
                // 之前没有合并过
                TAppPickPlan existPickPlan = existPickPlanList.stream().filter(pickPlan -> Objects.equals(pickPlan.getStandId(), beforeMergePickPlan.getStandId())
                        && Objects.equals(pickPlan.getVehicleId(), beforeMergePickPlan.getVehicleId())
                        && Objects.equals(pickPlan.getGoodsId(), beforeMergePickPlan.getGoodsId())
                        && Objects.equals(pickPlan.getPickType(), beforeMergePickPlan.getPickType())
                        && Objects.equals(pickPlan.getWorkIndex(), beforeMergePickPlan.getWorkIndex())).findFirst().orElse(null);
                if (existPickPlan != null) {
                    // 已经存过表
                    existPickPlan.setPlanPickQty(existPickPlan.getPlanPickQty() + beforeMergePickPlan.getPlanPickQty());
                    mergedPickPlanMap.put(key, existPickPlan);
                } else {
                    // 没有存过表
                    existPickPlan = new TAppPickPlan(
                            beforeMergePickPlan.getPlanId(),
                            beforeMergePickPlan.getVehicleId(),
                            beforeMergePickPlan.getGoodsId(),
                            beforeMergePickPlan.getPlanPickQty(),
                            beforeMergePickPlan.getPickType(),
                            beforeMergePickPlan.getWorkIndex(),
                            beforeMergePickPlan.getStandId()
                    );
                }
                mergedPickPlanMap.put(key, existPickPlan);
            }
        }
        return new ArrayList<>(mergedPickPlanMap.values());
    }

    /**
     * 这个库位是否可以出库
     *
     * @param locationId      库位号
     * @param equipVehicleMap 堆垛机与载具的映射
     * @return 结果true：可以出库，false：不可以出库
     */
    private boolean ifThisLocationCantOut(String locationId, Map<Integer, String> equipVehicleMap) {
        TAppLocation location = appCommon.getInstantLocationByLocationId(locationId);
        if (location == null || location.getIsLock() == 1) {
            return true;
        }
        return !equipVehicleMap.containsKey(location.getEquipmentId()) || !Objects.equals(equipVehicleMap.get(location.getEquipmentId()), "");
    }

    /**
     * 更新载具设备map
     *
     * @param equipVehicleMap 载具设备map
     * @param vehicleId       载具号
     * @param locationId      库位号
     */
    private void updateVehicleEquipMapByLocation(Map<Integer, String> equipVehicleMap, String vehicleId, String locationId) {
        TAppLocation location = appCommon.getInstantLocationByLocationId(locationId);
        if (location == null) {
            return;
        }
        if (equipVehicleMap.containsKey(location.getEquipmentId())) {
            equipVehicleMap.replace(location.getEquipmentId(), vehicleId);
        }
    }

    /**
     * 添加待删除序号以及记录
     * @param outIds 待删除id列表
     * @param thisOuts 待删除outs
     * @param addRecords 待添加的记录
     */
    private void addRemovingOutsAndRecord(List<String> outIds, TAppOuts thisOuts, List<TAppOutsRecord> addRecords) {
        outIds.add(thisOuts.getTaskId());
        addRecords.add(new TAppOutsRecord(
                thisOuts.getTaskId(),
                thisOuts.getGoodsId(),
                thisOuts.getVehicleId(),
                thisOuts.getNeedNum(),
                thisOuts.getDistributeNum(),
                thisOuts.getPickNum(),
                thisOuts.getOutType(),
                thisOuts.getDestination(),
                thisOuts.getUserName()
        ));
    }
}
