package com.prolog.cs.biz.outbound.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.TimeInterval;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import com.prolog.common.RestMsgHelper;
import com.prolog.cs.basic.chain.model.cargo.BaseCargoOwnerMst;
import com.prolog.cs.basic.chain.model.customer.BaseCustomerMst;
import com.prolog.cs.basic.chain.model.customer.vo.BaseCustomerMstRequestVO;
import com.prolog.cs.basic.chain.model.supplier.BaseSupplierMst;
import com.prolog.cs.basic.common.model.BaseCommonDict;
import com.prolog.cs.basic.common.model.SysPrintStrategy;
import com.prolog.cs.basic.common.model.SysPrintStrategyPerson;
import com.prolog.cs.basic.common.model.print.PrintParam;
import com.prolog.cs.basic.common.model.print.PrintStrategyParam;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.item.model.BaseMtlItemUomConversions;
import com.prolog.cs.basic.item.model.vo.ItemMstQueryVO;
import com.prolog.cs.basic.item.model.vo.ItemMstVO2;
import com.prolog.cs.basic.item.model.vo.WaveItemInfoVO;
import com.prolog.cs.basic.warehouse.model.BaseWmsWarehouseArea;
import com.prolog.cs.basic.warehouse.model.BaseWmsWhWorkstation;
import com.prolog.cs.basic.warehouse.model.dto.WmsWhBldgDTO;
import com.prolog.cs.basic.warehouse.model.vo.ContainerQueryVO;
import com.prolog.cs.basic.warehouse.model.vo.WarehouseLocatorBasicInfo;
import com.prolog.cs.biz.inbound.dto.IsSuperviseDTO;
import com.prolog.cs.biz.inbound.model.SupervisionCode;
import com.prolog.cs.biz.outbound.convert.TaskConvert;
import com.prolog.cs.biz.outbound.dao.*;
import com.prolog.cs.biz.outbound.enums.PickTaskDFLowStatus;
import com.prolog.cs.biz.outbound.enums.PickTaskHStatus;
import com.prolog.cs.biz.outbound.funcflow.OutBoundFunc;
import com.prolog.cs.biz.outbound.model.*;
import com.prolog.cs.biz.outbound.model.constant.DoPrintConstant;
import com.prolog.cs.biz.outbound.model.dto.*;
import com.prolog.cs.biz.outbound.model.dto.print.PrintAllVO;
import com.prolog.cs.biz.outbound.model.entity.*;
import com.prolog.cs.biz.outbound.model.out.ContainerBindTaskDto;
import com.prolog.cs.biz.outbound.model.out.OutboundTaskBindDetail;
import com.prolog.cs.biz.outbound.model.print.PrintDataWithMark;
import com.prolog.cs.biz.outbound.model.vo.InfTaskOutBackVO;
import com.prolog.cs.biz.outbound.model.vo.InfTaskOutVO;
import com.prolog.cs.biz.outbound.model.vo.PickTaskConfirmVO;
import com.prolog.cs.biz.outbound.model.vo.UpdateStockVO;
import com.prolog.cs.biz.outbound.model.vo.check.InnerCheckTaskDV2VO;
import com.prolog.cs.biz.outbound.resource.*;
import com.prolog.cs.biz.outbound.service.*;
import com.prolog.cs.biz.outbound.service.strategy.STRATEGY_CODE;
import com.prolog.cs.biz.outbound.service.strategy.StrategySelector;
import com.prolog.cs.biz.outbound.service.strategy.handles.IStrategyHandle;
import com.prolog.cs.biz.outbound.utils.BillUtils;
import com.prolog.cs.biz.outbound.utils.TransactionHelper;
import com.prolog.cs.platform.power.model.Employee;
import com.prolog.entity.vo.*;
import com.prolog.enums.OutBoundRequestEnum;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.properties.AuthProperties;
import com.prolog.framework.authority.properties.AuthRedisProperties;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.authority.util.HystrixVarUtil;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.common.print.PrintData;
import com.prolog.framework.bz.common.print.ReportData;
import com.prolog.framework.bz.core.collection.ValidList;
import com.prolog.framework.bz.core.model.ModelUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.ParameterException;
import com.prolog.framework.core.exception.PrologException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.*;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.lock.DistributedLock;
import com.prolog.framework.toolkit.MapToolKit;
import com.prolog.framework.utils.*;
import com.prolog.function.annotation.Flow;
import com.prolog.function.annotation.FuncImpl;
import com.prolog.fx.inf.core.Exception.RetryException;
import com.prolog.fx.inf.core.InterfaceType;
import com.prolog.fx.inf.core.StandardInterface;
import com.prolog.fx.inf.core.annotation.InterfaceMethod;
import com.prolog.fx.inf.core.dto.SimpleLog;
import com.prolog.inte.EisHandler;
import com.prolog.upcloud.base.inventory.vo.*;
import com.prolog.upcloud.base.strategy.model.BusinessControl;
import com.prolog.upcloud.base.wh.operate.vo.MoveConfirmParamsVO;
import com.prolog.upcloud.base.wh.operate.vo.ReplenishDetailVO;
import com.prolog.upcloud.base.wh.operate.vo.WmsAdjustAddVO;
import jodd.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicInteger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.prolog.constant.EisBusinessConstant.EIS;
import static com.prolog.cs.biz.outbound.enums.PickTaskDFLowStatus.*;
import static java.util.stream.Collectors.toList;

/**
 * @author zzz
 * @desc 拣选任务类
 * @date 2021/4/30
 */
@Service
public class PickTaskServiceImpl implements PickTaskService, StandardInterface<InterfaceBill, Object> {

    private static Logger log = LoggerFactory.getLogger(PickTaskServiceImpl.class);

    @Autowired
    private CommonClient commonClient;

    @Autowired
    private ItemClient itemClient;

    @Autowired
    private WaveBillDMapper waveBillDMapper;

    @Autowired
    private EisOutBoundResource eisOutboundClient;

    @Autowired
    private PickTaskHMapper pickTaskHMapper;

    @Autowired
    private PickTaskDMapper pickTaskDMapper;

    @Autowired
    private WmsTaskOutBackMapper wmsTaskOutBackMapper;

    @Autowired
    private WaveStorageMapper waveStorageMapper;

    @Autowired
    private UserTemplate userTemplate;

    @Resource
    private EisHandler eisHandler;

    @Autowired
    private PowerResource powerResource;

    @Autowired
    private WarehouseResource warehouseResource;

    @Autowired
    private PickOrderMapper pickOrderMapper;

    @Autowired
    private BarcodeHMapper barcodeHMapper;

    @Autowired
    private BarcodeDMapper barcodeDMapper;

    @Autowired
    private ControlResource controlResource;

    @Autowired
    private StrategyResource strategyResource;

    @Autowired
    private SaleRedRecordMapper saleRedRecordMapper;

    @Autowired
    private WaveBillMapper billMapper;

    @Autowired
    private WaveBillDMapper billDMapper;

    @Autowired
    private WaveMapper waveMapper;

    @Autowired
    private InventoryResource invClient;

    @Autowired
    private MoveTaskMapper moveTaskMapper;

    @Autowired
    InBoundClient inBoundClient;

    @Autowired
    WorkStageService workStageService;

    @Autowired
    private OperateResource operateResource;

    @Autowired
    private GspResource gspResource;

    @Autowired
    WorkStageRuntimeMapper workStageRuntimeMapper;

    @Autowired
    protected DistributedLock distributedLock;

    @Autowired
    private IntegrationResource integrationResource;

    @Autowired
    private OutcomingRecordHMapper outcomingRecordHMapper;

    @Autowired
    private OutcomingRecordDMapper outcomingRecordDMapper;

    @Autowired
    private WmsMoveTaskRefMapper wmsMoveTaskRefMapper;

    @Autowired
    private ChainResource chainResource;

    @Autowired
    private WmsTaskOutBackMapper outBackMapper;

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private OmsDoBillHMapper omsDoBillHMapper;

    @Value("${prolog.interfaceId.sendAgv}")
    private String sendAgv;

    @Value("${prolog.interfaceId.sendWms}")
    private String sendWms;

    @Value("${prolog.interfaceId.updateAgvStatus}")
    private String updateAgvStatus;

    @Value("${prolog.interfaceId.token:$2a$12$PHVUZPLUswQVz0Mj.FdzmeF5lC.eqQEGOtA8CN8OzpH7XC8Mf3ste}")
    private String integrationToken;

    @Value("${prolog.dao.keyGenerator.snowFlake.dataCenterId:15}")
    private long dataCenterId;

    @Value("${prolog.dao.keyGenerator.snowFlake.machineId:2}")
    private long machineId;
    @Autowired
    private AuthProperties authProperties;

    // 业务参数配置内/外复核回传ERP by Huanglh 20220112
    @Autowired
    private StrategySelector strategySelector;

    @Autowired
    private WmsTaskOutMapper wmsTaskOutMapper;

    @Value("${oms.outComingRecordBack}")
    private String outComingRecordBack;

    @Value("${eis.infTaskOutUrl}")
    private String infTaskOutUrl;

    @Autowired
    private PickTaskServiceImpl pickTaskServiceImpl;

    @Autowired
    private PickTaskAppServiceImpl pickTaskAppService;

    @Autowired
    private OrderOutboundStatusBackService orderOutboundStatusBackService;

    @Autowired
    private PrintService printService;

    @Resource
    private TaskConvert taskConvert;

    @Autowired
    private PickTaskServiceImpl pickTaskService;

    @Autowired
    private WmsFaceOrderMapper wmsFaceOrderMapper;

    @Autowired
    private PrintLogService printLogService;
    @Autowired
    private PrintLogMapper printLogMapper;

    @Autowired
    private OmsDoBillDMapper omsDoBillDMapper;
    @Autowired
    private WmsRepPreMapper wmsRepPreMapper;

    OutBoundFunc.getAreaCodes getAreaCodes;
    OutBoundFunc.getPickTaskHList getPickTaskHList;
    OutBoundFunc.getWorkstation getWorkstation;
    OutBoundFunc.savePickOrder savePickOrder;
    OutBoundFunc.savePickOrder3 savePickOrder3;
    OutBoundFunc.getPickTaskHListByBill getPickTaskHListByBill;
    OutBoundFunc.updatePickTaskH updatePickTaskH;
    OutBoundFunc.confirmReplenish confirmReplenish;
    OutBoundFunc.saveBarcode saveBarcode;
    OutBoundFunc.updateStock updateStock;
    OutBoundFunc.updateStock2 updateStock2;
    OutBoundFunc.saveOutcomingRecord saveOutcomingRecord;

    @PostConstruct
    public void init() {
        getAreaCodes = this::getAreaCodes;
        getPickTaskHList = this::getPickTaskHList;
        getWorkstation = this::getWorkstation;
        savePickOrder = this::savePickOrder;
        savePickOrder3 = this::savePickOrder3;
        getPickTaskHListByBill = this::getPickTaskHListByBill;
        updatePickTaskH = this::updatePickTaskH;
        confirmReplenish = this::confirmReplenish;
        saveBarcode = this::saveBarcode;
        updateStock = this::updateStock;
        updateStock2 = this::updateStock2;
        saveOutcomingRecord = this::saveOutcomingRecord;
    }

    /**
     * 索取任务(整件)
     *
     * @param operatorCode 工号
     * @param warehouseId  仓库id
     * @param isPrint      是否自动打印
     */
    @Flow(name = "整件索取", category = "出库/拣选单管理/索取任务/整件索取", index = 0, description = "1.根据工号/仓库id/业务类型/作业类型查询员工作业库区编码集合;"
            + "\n2.根据员工作业区域编码查询 wms_pick_task_h表,status为0、pick_task_type为0 的拣货任务;"
            + "\n3.更新表:wms_pick_task_h,字段:状态(status)=1"
            + "\n4.拣选单表wms_pick_order新增一条数据;")
    @Transactional
    @Override
    public Map<String, Object> createPickOrder2(String bldgId, String operatorCode, String warehouseId, Integer isPrint, String pickTaskId, String containerNo, Integer type) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        Map<String, Object> returnMap = new HashMap<>();
        List<Integer> pickTaskTypes = new ArrayList<>();
        String businesstype;
        // 获取员工作业类型 type 0：普通任务；1：特殊任务
        if (type == 0) {
            businesstype = "2011";
            pickTaskTypes.add(0);
        } else {
            businesstype = "2011";
            pickTaskTypes.add(4);
        }
        RestMessage<String> restMessage1 = controlResource.getWorkType(operatorCode, warehouseId, businesstype);
        if (!restMessage1.isSuccess())
            throw new RuntimeException("获取员工作业类型失败！" + restMessage1.getMessage());
        String workType = restMessage1.getData();
        if (StringUtils.isEmpty(workType))
            throw new BizException("该员工未配置，整件拣货/特殊拣货权限");
        //获取员工作业库区编码集合
        /*
            "dictCode": "WHOLE_PICKING",
            "dictName": "仅整件拣货",
            "dictCode": "WHOLE_PICKING_FIRST",
            "dictName": "整件拣货优先",
            "dictCode": "WHOLE_REPLENISH_FIRST",
            "dictName": "整件补货优先",
            "dictCode": "WHOLE_REPLENISH",
            "dictName": "仅整件补货",
         */
        List<String> areaCodes;
        try {
            areaCodes = getAreaCodes(operatorCode, warehouseId, "2011", "WHOLE_PICKING");
        } catch (Exception e) {
            areaCodes = new ArrayList<>();
        }
        List<String> areaCodes2;
        try {
            areaCodes2 = getAreaCodes(operatorCode, warehouseId, "2011", "WHOLE_PICKING_FIRST");
        } catch (Exception e) {
            areaCodes2 = new ArrayList<>();
        }
        List<String> areaCodes3;
        try {
            areaCodes3 = getAreaCodes(operatorCode, warehouseId, "2011", "WHOLE_REPLENISH");
        } catch (Exception e) {
            areaCodes3 = new ArrayList<>();
        }
        List<String> areaCodes4;
        try {
            areaCodes4 = getAreaCodes(operatorCode, warehouseId, "2011", "WHOLE_REPLENISH_FIRST");
        } catch (Exception e) {
            areaCodes4 = new ArrayList<>();
        }
        areaCodes.addAll(areaCodes2);
        areaCodes.addAll(areaCodes3);
        areaCodes.addAll(areaCodes4);
        if (CollUtil.isEmpty(areaCodes)) {
            throw new BizException("该员工未配置，整件拣货权限");
        }
        // 任务数
        int count = 1;
        // 拣货方式：0-整散分开索取；1-整单索取
        List<PickTaskH> list;
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"PICK_TASK_NUM"}, warehouseId, null, enterpriseId, bldgId);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> map = restMessage.getData();
            if (map.containsKey("PICK_TASK_NUM"))
                count = Integer.parseInt(map.get("PICK_TASK_NUM").getRegValue());
        }
        // 索取件数必须小于最大拣货件数
        String[] pickTaskIds;
        String[] containerNos;
        if (StringUtils.isBlank(pickTaskId)) {
            pickTaskIds = null;
        } else {
            pickTaskIds = pickTaskId.split(",");
        }
        if (StringUtils.isBlank(containerNo)) {
            containerNos = null;
        } else {
            containerNos = containerNo.split(",");
        }
        list = pickTaskHMapper.getPickTaskWholeList(bldgId, null, enterpriseId, warehouseId, count, pickTaskTypes, areaCodes, workType, pickTaskIds, containerNos);
        if (list == null || list.size() == 0) {
            returnMap.put("count", 0);
            return returnMap;
        }
        String pickOrderId = String.valueOf(SnowFlakeUtils.getId(dataCenterId, machineId));
        List<String> pickTaskDIds = new ArrayList<>();

        String[] pickTaskHIds = list.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
        List<PickTaskH> finalList = list;
        try {
            boolean result = distributedLock.multiLock(pickTaskHIds, () ->
                    //更新拣货任务主表,保存外复核数据
                    saveBarcode.saveBarcode(finalList, pickTaskDIds, pickOrderId, bldgId, warehouseId, enterpriseId)
            );
            if (!result) {
                throw new BizException("拣货索取失败！");
            }
        } catch (Exception e) {
            throw new PrologException("拣货索取失败！" + e.getMessage());
        }

        String[] hIds = list.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
        this.updatePickTaskD(hIds, enterpriseId, "2");

        savePickOrder3.savePickOrder3(pickOrderId, userDTO.getId(), operatorCode, operatorName, warehouseId, list.size(), 0, isPrint);
        if (isPrint == 1 && pickTaskDIds.size() > 0) {
            // 调打印查询接口
            List<PrintDataWithMark> printDataList = new ArrayList<>();
            Map<Integer, List<PickTaskH>> collect = list.stream().collect(Collectors.groupingBy(PickTaskH::getType));
            for (Integer taskType : collect.keySet()) {
                if (CollUtil.isNotEmpty(collect.get(taskType))) {
                    printDataList.addAll(this.printWholeLabels(pickTaskDIds, null, warehouseId, taskType, operatorName));
                }
            }
            if (CollUtil.isNotEmpty(printDataList)) {
                Map<String, List<PrintDataWithMark>> map = printDataList.stream().collect(Collectors.groupingBy(PrintDataWithMark::getDataMark));
                List<Map<String, Object>> printDataList1 = new ArrayList<>();
                for (String s : map.keySet()) {
                    Map<String, Object> temp = new HashMap<>();
                    temp.put("printMark", s);
                    temp.put("printData", map.get(s));
                    printDataList1.add(temp);
                }
                // 返回打印数据
                returnMap.put("printDataList", printDataList1);
            }
        }
        returnMap.put("count", list.size());
        returnMap.put("pickOrderId", pickOrderId);
        return returnMap;
    }

    /**
     * 索取任务(零货)
     *
     * @param operatorCode 工号
     */
    @Flow(name = "零货索取", category = "出库/拣选单管理/索取任务/零货索取", index = 0, description = "1.根据工号/仓库id/业务类型/作业类型查询员工作业库区编码集合;"
            + "\n2.根据员工作业区域编码查询待拣货任务;"
            + "\n3.根据任务库区找复核台，同订单同库区尽可能放同一个复核台;"
            + "\n4.生成拣选单;")
    @Override
    @Transactional
    public Map<String, Object> createPickOrder(String bldgId, String operatorCode, String containerCode, String warehouseId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        Employee employee = this.getEmployee(operatorCode, enterpriseId);
        Map<String, Object> returnMap = new HashMap<>();
        // 查询待索取任务
        List<PickTaskH> list = getPickTaskHList.getPickTaskHList(bldgId, operatorCode, warehouseId, enterpriseId, returnMap);
        if (list.size() > 0) {
            String pickOrderId = String.valueOf(SnowFlakeUtils.getId(dataCenterId, machineId));
            returnMap.put("pickOrderId", pickOrderId);
            Map<String, BaseWmsWhWorkstation> stationMap = new HashMap<>();
            for (PickTaskH pickTaskH : list) {
                // 找复核台
                BaseWmsWhWorkstation workstation = getWorkstation.getWorkstation(pickTaskH, stationMap);
                // 更新拣货任务主表
                updatePickTaskH.updatePickTaskH(pickTaskH, pickOrderId, workstation);
            }
            String[] hIds = list.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
            this.updatePickTaskD(hIds, enterpriseId, "2");
            // 保存拣选单
            savePickOrder.savePickOrder(pickOrderId, employee, warehouseId, list.size(), 1);
        }
        return returnMap;
    }

    /**
     * 索取任务(功能库房)
     *
     * @param operatorCode
     * @param warehouseId
     * @param isPrint
     */
    @Flow(name = "功能库房索取", category = "出库/拣选单管理/索取任务/功能库房索取", index = 0, description = "1.根据工号/仓库id/业务类型/作业类型查询员工作业库区编码集合;"
            + "\n2.根据员工作业区域编码查询 wms_pick_task_h表,status为0、pick_task_type为2 的拣货任务;"
            + "\n3.根据任务库区找复核台，同订单同库区尽可能放同一个复核台;"
            + "\n4.更新表:wms_pick_task_h,字段:状态(status)=1,复核台相关字段"
            + "\n5.拣选单表wms_pick_order新增一条数据;")
    @Transactional
    @Override
    public Map<String, Object> createPickOrder3(String bldgId, String operatorCode, String containerCode, String warehouseId, Integer isPrint) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        Map<String, Object> map = new HashMap<>();
        // 查询未上架的补货任务
        Integer notFinishCount = pickTaskHMapper.getNotFinishCount(warehouseId, operatorCode);
        if (notFinishCount > 0)
            throw new BizException("请先上架确认补货任务");
        // 获取员工作业库区编码集合
        List<String> areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", "WHOLE_BULK_PICKING");

        // 功能库房新增了整货，零货，所以需要先检查是否有补货单
        // 任务数--->功能库房固定一个任务包组一个拣货单
        int count = 1;
        //查询当天最后的补货订单编号
        List<PickTaskH> pickTaskHList = new ArrayList<>();
        String billGroupId = pickTaskHMapper.getLastMoveBillId(warehouseId, operatorCode, 2);
        if (billGroupId != null) {
            // 查询该补货订单的拣货任务
            pickTaskHList = pickTaskHMapper.getPickTaskHListByBill3(bldgId, billGroupId, warehouseId, areaCodes, operatorCode, 2);
        }
        // 查询补货任务
        if (pickTaskHList == null || pickTaskHList.size() == 0) {
            pickTaskHList = pickTaskHMapper.getPickTaskHListByMove(bldgId, enterpriseId, warehouseId, count, areaCodes, null, operatorCode, 2);
        }
        // 无补货任务
        if (pickTaskHList.size() == 0) {
            // 按工号索取一个订单的拣货任务
            pickTaskHList = pickTaskHMapper.getPickTaskHListByBill(bldgId, enterpriseId, warehouseId, areaCodes, "1");
        }

        map.put("count", pickTaskHList.size());
        if (pickTaskHList.size() > 0) {
            String pickOrderId = String.valueOf(SnowFlakeUtils.getId(dataCenterId, machineId));
            Map<String, BaseWmsWhWorkstation> stationMap = new HashMap<>();
            BaseWmsWhWorkstation workstation = null;
            for (PickTaskH pickTaskH : pickTaskHList) {
                // 河南省医药 固定机动复核台
                // 找复核台
                workstation = new BaseWmsWhWorkstation();
                workstation.setStationId("-1");
                workstation.setStationName("-1");
                workstation.setStationCode("-1");
                // 更新拣货任务主表
                updatePickTaskH.updatePickTaskH(pickTaskH, pickOrderId, workstation);
            }
            String[] hIds = pickTaskHList.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
            this.updatePickTaskD(hIds, enterpriseId, "2");
            // 新增拣选单数据
            savePickOrder3.savePickOrder3(pickOrderId, userDTO.getId(), operatorCode, operatorName, warehouseId, pickTaskHList.size(), 2, isPrint);
            map.put("pickOrderId", pickOrderId);
            if (isPrint == 1) {
                // 调打印查询接口
                List<PrintData> printDataList = this.printPaperSlip(Collections.singletonList(pickOrderId), warehouseId, bldgId, "2");
                // 返回打印数据
                map.put("printDataList", printDataList);
            }
        }
        return map;
    }

    /**
     * 索取任务(整单)
     *
     * @param bldgId
     * @param operatorCode
     * @param containerCode
     * @param warehouseId
     * @param isPrint
     * @return
     */
    @Transactional
    @Override
    public Map<String, Object> createPickOrder4(String bldgId, String operatorCode, String containerCode, String warehouseId, Integer isPrint) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        Map<String, Object> map = new HashMap<>();
        Integer workingCount = pickTaskHMapper.getUnConfirmPickCount(operatorCode, warehouseId);
        if (workingCount > 0)
            throw new BizException("当前有未完成的拣货任务!");
        // 查询未上架的拣货任务
        Integer notFinishCount = pickTaskHMapper.getNotFinishCount(warehouseId, operatorCode);
        if (notFinishCount > 0)
            throw new BizException("请先上架确认补货任务");
        // 获取员工作业库区编码集合
        List<String> areaCodes = new ArrayList<>();
        // 零货
        try {
            areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", "BULK_PICKING");
        } catch (Exception e) {
        }
        //整件
        RestMessage<String> restMessage1 = controlResource.getWorkType(operatorCode, warehouseId, "2011");
        if (!restMessage1.isSuccess())
            throw new RuntimeException("获取员工作业类型失败！" + restMessage1.getMessage());
        String workType = restMessage1.getData();
        if (StringUtils.isEmpty(workType))
            throw new BizException("该员工未配置，整件拣货/补货作业权限");
        List<String> areaCodes2 = this.getAreaCodes(operatorCode, warehouseId, "2011", workType);
        areaCodes.addAll(areaCodes2);
        // 任务数
        Integer count = 1;
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"PICK_TASK_NUM"}, warehouseId, null, enterpriseId, bldgId);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> result = restMessage.getData();
            if (result.containsKey("PICK_TASK_NUM"))
                count = Integer.valueOf(result.get("PICK_TASK_NUM").getRegValue());
        }
        List<PickTaskH> list = null;
        // 查询当天最后的补货订单编号
        String billGroupId = pickTaskHMapper.getLastMoveBillId(warehouseId, operatorCode, null);
        if (billGroupId != null)
            // 查询该补货订单的拣货任务
            list = pickTaskHMapper.getPickTaskHListByBill3(bldgId, billGroupId, warehouseId, areaCodes, operatorCode, null);
        // 查询补货任务
        if (list == null || list.size() == 0)
            list = pickTaskHMapper.getPickTaskHListByMove(bldgId, enterpriseId, warehouseId, count, areaCodes, workType, operatorCode, null);
        // 无补货任务,则索取整单任务
        if (list.size() == 0) {
            list = pickTaskHMapper.getPickTaskHListByBill2(bldgId, enterpriseId, warehouseId, areaCodes, "0", operatorCode);
        }
        map.put("count", list.size());
        if (list.size() > 0) {
            String pickOrderId = String.valueOf(SnowFlakeUtils.getId(dataCenterId, machineId));
            Map<String, BaseWmsWhWorkstation> stationMap = new HashMap<>();
            BaseWmsWhWorkstation workstation = null;
            for (PickTaskH pickTaskH : list) {
                pickTaskH.setPickOrderId(pickOrderId);
                pickTaskH.setStatus("1");
                if (pickTaskH.getPickTaskType() != 0 && pickTaskH.getType() == 0) {
                    String areaCode = pickTaskH.getWarehouseAreaCode();
                    List<String> stationIds = this.getWorkstationIds(areaCode, warehouseId);
                    // 找同订单同库区的复核台
                    List<BaseWmsWhWorkstation> stationList = pickTaskHMapper.getStationByBillId(pickTaskH.getPickTaskId(), null, stationIds);
                    if (stationList.size() > 0) {
                        workstation = stationList.get(0);
                        stationMap.put(areaCode, workstation);
                    } else if (!stationMap.isEmpty() && stationMap.containsKey(areaCode)) {
                        // 找同库区的复核台
                        workstation = stationMap.get(areaCode);
                    } else {
                        workstation = this.getBaseWmsWhWorkstation(areaCode, warehouseId, enterpriseId);
                        stationMap.put(areaCode, workstation);
                    }
                    pickTaskH.setStationId(workstation.getStationId());
                    pickTaskH.setStationName(workstation.getStationName());
                    pickTaskH.setStationCode(workstation.getStationCode());
                }
                pickTaskHMapper.updateFields(pickTaskH, FieldSelector.newInstance().include(new String[]{"status", "pickOrderId", "stationCode", "stationName", "stationId"}));
            }

            updatePickTaskD4WholeOrderPick(userDTO, enterpriseId, list);
            PickOrder pickOrder = new PickOrder();
            pickOrder.setPickOrderId(pickOrderId);
            pickOrder.setStatus("0");
            pickOrder.setWarehouseId(warehouseId);
            pickOrder.setTaskCount(list.size());
            pickOrder.setOperatorId(userDTO.getId());
            pickOrder.setOperatorName(operatorName);
            pickOrder.setOperatorCode(operatorCode);
            pickOrder.setPickTaskType(list.get(0).getPickTaskType());
            // 如果自动打印
            if (isPrint == 1) {
                pickOrder.setPrintStatus("1");
            } else {
                pickOrder.setPrintStatus("0");
            }
            ModelUtils.generateBaseData(pickOrder, userTemplate::getUserDTO);
            pickOrderMapper.save(pickOrder);
            map.put("pickOrderId", pickOrderId);
        }
        return map;
    }

    /**
     * 索取任务(整件)
     *
     * @param operatorCode 工号
     * @param warehouseId  仓库id
     * @param isPrint      是否自动打印
     */
    @Flow(name = "整件索取", category = "出库/拣选单管理/索取任务/整件索取", index = 0, description = "1.根据工号/仓库id/业务类型/作业类型查询员工作业库区编码集合;"
            + "\n2.根据员工作业区域编码查询 wms_pick_task_h表,status为0、pick_task_type为0 的拣货任务;"
            + "\n3.更新表:wms_pick_task_h,字段:状态(status)=1"
            + "\n4.拣选单表wms_pick_order新增一条数据;")
    @Transactional
    @Override
    public Map<String, Object> createPickOrder5(String bldgId, String operatorCode, String warehouseId, Integer isPrint, String pickTaskId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        Map<String, Object> returnMap = new HashMap<>();
        // 获取员工作业类型
        RestMessage<String> restMessage1 = controlResource.getWorkType(operatorCode, warehouseId, "2011");
        if (!restMessage1.isSuccess())
            throw new RuntimeException("获取员工作业类型失败！" + restMessage1.getMessage());
        String workType = restMessage1.getData();
        if (StringUtils.isEmpty(workType))
            throw new BizException("该员工未配置，特殊拣货权限");
        // 获取员工作业库区编码集合
        List<String> areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", workType);

        // 任务数
        Integer count = 4;
        // 拣货方式：0-整散分开索取；1-整单索取
        List<PickTaskH> list;
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"PICK_TASK_NUM", "PICK_TASK_ASK_WAY", "PICK_TASK_MAX_PCS"}, warehouseId, null, enterpriseId, bldgId);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> map = restMessage.getData();
            if (map.containsKey("PICK_TASK_NUM"))
                count = Integer.valueOf(map.get("PICK_TASK_NUM").getRegValue());
        }
        List<Integer> pickTaskTypes = new ArrayList<>();
        pickTaskTypes.add(4);
        // 索取件数必须小于最大拣货件数
        list = pickTaskHMapper.getSpecialPickTaskList(bldgId, null, enterpriseId, warehouseId, count, pickTaskTypes, areaCodes, workType);

        if (list == null || list.size() == 0) {
            returnMap.put("count", 0);
            return returnMap;
        }

        String pickOrderId = String.valueOf(SnowFlakeUtils.getId(dataCenterId, machineId));
        List<String> pickTaskDIds = new ArrayList<>();

        String[] pickTaskHIds = list.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
        List<PickTaskH> finalList = list;
        try {
            boolean result = distributedLock.multiLock(pickTaskHIds, () ->
                    // 更新拣货任务主表,保存外复核数据
                    saveBarcode.saveBarcode(finalList, pickTaskDIds, pickOrderId, bldgId, warehouseId, enterpriseId)
            );
            if (!result) {
                throw new BizException("拣货索取失败！");
            }
        } catch (Exception e) {
            throw new PrologException("拣货索取失败！" + e.getMessage());
        }

        String[] hIds = list.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
        this.updatePickTaskD(hIds, enterpriseId, "2");

        savePickOrder3.savePickOrder3(pickOrderId, userDTO.getId(), operatorCode, operatorName, warehouseId, list.size(), 0, isPrint);
        if (isPrint == 1 && pickTaskDIds.size() > 0) {
            // 调打印查询接口
            List<PrintDataWithMark> printDataList = new ArrayList<>();
            Map<Integer, List<PickTaskH>> collect = list.stream().collect(Collectors.groupingBy(PickTaskH::getType));
            for (Integer type : collect.keySet()) {
                if (CollUtil.isNotEmpty(collect.get(type))) {
                    printDataList.addAll(this.printWholeLabels(pickTaskDIds, null, warehouseId, type, operatorName));
                }
            }
            // 返回打印数据
            if (CollUtil.isNotEmpty(printDataList)) {
                Map<String, List<PrintDataWithMark>> map = printDataList.stream().collect(Collectors.groupingBy(PrintDataWithMark::getDataMark));
                List<Map<String, Object>> printDataList1 = new ArrayList<>();
                for (String s : map.keySet()) {
                    Map<String, Object> temp = new HashMap<>();
                    temp.put("printMark", s);
                    temp.put("printData", map.get(s));
                    printDataList1.add(temp);
                }
                // 返回打印数据
                returnMap.put("printDataList", printDataList1);
            }
        }
        returnMap.put("count", list.size());
        returnMap.put("pickOrderId", pickOrderId);
        return returnMap;
    }

    /**
     * 拣货确认
     */
    public void pickConfirm(
            PickTaskConfirmVO vo,
            String enterpriseId,
            String warehouseId,
            String operatorCode,
            String operatorName,
            String operatorId,
            Date date,
            String[] pickTaskDIds,
            List<String> lineIds,
            List<ReplenishDetailVO> replenishDetailVOList,
            List<String> taskDIds,
            PickTaskH pickTaskH,
            PickTaskD pickTaskD
    ) {
        String pickTaskDId = vo.getPickTaskDId();
        BigDecimal pickQty = vo.getPickQty();
        String pickTaskId = pickTaskD.getPickTaskId();
        if (pickTaskH.getPickTaskType() != 0 && StringUtils.isEmpty(pickTaskH.getContainerCode())) {
            // 增加判断是否是功能库房的补货任务，是的话，也不检查绑定容器
            if (!(2 == pickTaskH.getPickTaskType() && 1 == pickTaskH.getType())) {
                throw new ParameterException("请先绑定容器！");
            }
        }
        if (pickQty == null)
            throw new ParameterException("拣货数量不能为空！");
        pickTaskDMapper.updateMapById(pickTaskDId, MapUtils.put("pickQty", pickQty).put("pickerId", operatorId).put("pickerNo", operatorCode).put("pickerName", operatorName).put("pickTime", date).put("flowStatus", "3").getMap(), PickTaskD.class);
        // 如果是补货任务，更新补货表状态
        if (pickTaskH.getType() == 1) {
            String moveId = pickTaskHMapper.getMoveTaskId(pickTaskDId, warehouseId);
            if (moveId != null) {
                MoveTaskDO move = moveTaskMapper.findById(moveId, MoveTaskDO.class);
                lineIds.add(move.getDetailId());
                ReplenishDetailVO replenishDetailVO = new ReplenishDetailVO();
                replenishDetailVO.setLineId(move.getDetailId());
                replenishDetailVO.setSrcLineId(pickTaskDId);
                replenishDetailVOList.add(replenishDetailVO);
                taskDIds.add(pickTaskDId);
            }
        }
        // 如果是整件任务，则将对应条码表更新为0-待复核索取
        if (pickTaskH.getPickTaskType() == 0) {
            List<BarCodeDDO> dList = barcodeDMapper.findByMap(MapUtils.put("wmsPickTaskDId", pickTaskDId).put("warehouseId", warehouseId).getMap(), BarCodeDDO.class);
            if (dList.size() > 0)
                barcodeHMapper.updateMapById(dList.get(0).getBarcodeId(), MapUtils.put("checkStatus", "0").getMap(), BarcodeHDO.class);
        }
        // 查询 拣选任务主表下明细未确认条数
        Integer count = pickTaskHMapper.getUnConfirmCount(pickTaskDIds, pickTaskDId, enterpriseId);
        // 如果明细都已确认，则任务主表状态更新为2：待复核
        if (count == 0) {
            // 任务主表状态更新
            if (pickTaskH.getType() == 1) {
                pickTaskHMapper.updateMapById(pickTaskId, MapUtils.put("status", "5").getMap(), PickTaskH.class);
            } else {
                pickTaskHMapper.updateMapById(pickTaskId, MapUtils.put("status", "2").getMap(), PickTaskH.class);
            }
            String pickOrderId = pickTaskH.getPickOrderId();
            // 查询未确认的拣选任务
            Integer count2 = pickTaskHMapper.getUnConfirmCountH(pickTaskId, pickOrderId, pickTaskH.getBldgId(), warehouseId);
            // 拣选单状态更新为2：拣选完成
            if (count2 == 0) {
                pickOrderMapper.updateMapById(pickOrderId, MapUtils.put("status", "2").getMap(), PickOrder.class);
                // 回传拣选完成状态
                if (pickTaskH.getType() == 0) {
                    orderOutboundStatusBackService.sendOutboundOrderStatusOms(pickTaskH.getBillGroupId(), "", "", "", "", "30", BigDecimal.ZERO);
                }
            }
        }
        BigDecimal redQty = BigDecimal.ZERO;
        if (pickTaskD.getPickRedType() != null && pickTaskD.getPickRedType().equals("0")) {
            redQty = pickTaskD.getSaleRedQty() == null ? redQty : pickTaskD.getSaleRedQty();
        }
        // 扣减库存,补货任务不扣库存
        if (pickTaskH.getType() == 0) {
            invStockConfirm(pickTaskD, warehouseId, redQty);
        }
    }

    /**
     * 冲红确认
     */
    public void redConfirm(PickTaskConfirmVO vo, String enterpriseId, String warehouseId, String operatorCode, String operatorName, String operatorId, Date date, List<UpdateStockVO> stockVOList, List<String> redOmsBillIds, PickTaskH pickTaskH, PickTaskD pickTaskD) {
        String pickTaskDId = vo.getPickTaskDId();
        BigDecimal saleRedQty = BigDecimal.ZERO;
        if (vo.getRedQty() == null)
            throw new ParameterException("冲红数量不能为空！");
        List<WaveBillDDO> billDDOList = pickTaskHMapper.getBillDList(enterpriseId, warehouseId, pickTaskD.getWaveStorageId());
        if (pickTaskD.getPickTaskType() != null && pickTaskD.getPickTaskType() == 0 && billDDOList.size() > 0) {
            BigDecimal[] results = vo.getRedQty().divideAndRemainder(billDDOList.get(0).getConversionRate());
            if (results[1].compareTo(BigDecimal.ZERO) > 0)
                throw new PrologException("整件红冲数量不能为零散数!");
        }
        BigDecimal qty = null;
        if (null == pickTaskD.getPickQty() || pickTaskD.getPickQty().compareTo(BigDecimal.ZERO) == 0) {
            qty = pickTaskD.getQty().subtract(vo.getRedQty());
        } else {
            qty = pickTaskD.getPickQty().subtract(vo.getRedQty());
        }
        saleRedQty = vo.getRedQty().add(pickTaskD.getSaleRedQty() == null ? BigDecimal.ZERO : pickTaskD.getSaleRedQty());
        pickTaskDMapper.updateMapById(pickTaskDId, MapUtils.put("pickQty", qty).put("saleRedQty", saleRedQty).put("pickRedType", vo.getMessageType()).getMap(), PickTaskD.class);

        // 如果是整件红冲，则更新对应外复核数量
        if (pickTaskH.getPickTaskType() == 0) {
            Criteria crt = Criteria.forClass(BarCodeDDO.class);
            Restriction r1 = Restrictions.eq("wmsPickTaskDId", pickTaskDId);
            Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
            crt.setRestriction(Restrictions.and(r1, r2));
            barcodeDMapper.updateMapByCriteria(MapUtils.put("qty", qty).getMap(), crt);
        }

        if (billDDOList.size() > 0) {
            SaleRedRecord saleRedRecord = new SaleRedRecord();
            saleRedRecord.setQty(vo.getRedQty());
            saleRedRecord.setReason(vo.getRedReason());
            saleRedRecord.setBillDId(billDDOList.get(0).getId());
            saleRedRecord.setItemId(billDDOList.get(0).getItemId());
            saleRedRecord.setSrcCode(billDDOList.get(0).getSrcCode());
            saleRedRecord.setStatus(0);
            saleRedRecord.setType(0);
            saleRedRecord.setPickerId(operatorId);
            saleRedRecord.setPickerName(operatorName);
            saleRedRecord.setPickerNo(operatorCode);
            saleRedRecord.setBldgId(pickTaskH.getBldgId());
            saleRedRecord.setWarehouseId(warehouseId);
            saleRedRecord.setEnterpriseId(enterpriseId);
            saleRedRecord.setCreator(operatorId);
            saleRedRecord.setCreatorName(operatorName);
            saleRedRecord.setGmtCreate(date);
            saleRedRecord.setSrcId(billDDOList.get(0).getSrcId());
            saleRedRecord.setSrcLineId(billDDOList.get(0).getSrcLineId());
            saleRedRecordMapper.save(saleRedRecord);
            // 出库预占调整
            UpdateStockVO updateStockVO = new UpdateStockVO();
            updateStockVO.setBillId(billDDOList.get(0).getBillId());
            updateStockVO.setBillDId(billDDOList.get(0).getId());
            updateStockVO.setPickTaskDId(pickTaskDId);
            updateStockVO.setRedQty(vo.getRedQty());
            stockVOList.add(updateStockVO);

            // 如果拣货明细全部红冲
            if (saleRedQty.compareTo(pickTaskD.getQty()) == 0) {
                pickTaskDMapper.updateMapById(pickTaskDId, MapUtils.put("flowStatus", "7").getMap(), PickTaskD.class);
                List<Integer> countList = pickTaskHMapper.getRedCount(billDDOList.get(0).getSrcId(), billDDOList.get(0).getSrcLineId(), enterpriseId);
                // 整单红冲则回传erp
                if (countList.size() > 1 && countList.get(0) == 0 && countList.get(1) == 0) {
                    String billGroupId = pickTaskH.getBillGroupId();
                    // 整单冲红
                    redOmsBillIds.add(billGroupId);

                    if (!StringUtils.isBlank(pickTaskH.getContainerCode())) {
                        // 释放容器
                        ContainerQueryVO containerQueryVO = new ContainerQueryVO();
                        containerQueryVO.setContainerCode(pickTaskH.getContainerCode());
                        containerQueryVO.setWarehouseId(pickTaskH.getWarehouseId());
                        warehouseResource.release(containerQueryVO);
                    }
                    // List<String> omsBillIds = barcodeHMapper.getOmsBillIds(billGroupId, enterpriseId);
                    /*if (omsBillIds.size() > 0) {
                        redOmsBillIds.addAll(omsBillIds);
                    }*/

                    Criteria crt1 = Criteria.forClass(PickTaskH.class);
                    Restriction r1 = Restrictions.eq("billGroupId", billGroupId);
                    Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
                    Restriction r3 = Restrictions.ne("status", "10");
                    crt1.setRestriction(Restrictions.and(r1, r2, r3));
                    pickTaskHMapper.updateMapByCriteria(MapUtils.put("status", "10").getMap(), crt1);

                    Criteria crt2 = Criteria.forClass(BarcodeHDO.class);
                    Restriction r4 = Restrictions.eq("billGroupId", billGroupId);
                    Restriction r5 = Restrictions.eq("warehouseId", warehouseId);
                    Restriction r6 = Restrictions.ne("checkStatus", "5");
                    crt2.setRestriction(Restrictions.and(r4, r5, r6));
                    barcodeHMapper.updateMapByCriteria(MapUtils.put("checkStatus", "5").getMap(), crt2);
                }
            }
        }
    }

    /**
     * 下架确认,扣减库存
     *
     * @param lineIds
     * @param replenishDetailVOList
     */
    @FuncImpl(name = "下架确认,扣减库存", func = OutBoundFunc.confirmReplenish.class, description = "下架确认,扣减库存")
    public void confirmReplenish(List<String> lineIds, List<ReplenishDetailVO> replenishDetailVOList) {
        if (lineIds.size() > 0) {
            MoveConfirmParamsVO vo = new MoveConfirmParamsVO();
            vo.setLineIds(lineIds.toArray(new String[lineIds.size()]));
            vo.setMoveFlag(0);
            vo.setReplenishDetailVOList(replenishDetailVOList);
            RestMessage restMessage = operateResource.confirmReplenish(vo);
            if (!restMessage.isSuccess()) {
                log.error("调用库存下架确认接口出错！" + restMessage.getMessage() + "，vo:" + JSON.toJSONString(vo));
                throw new PrologException("调用库存下架确认接口出错！" + restMessage.getMessage());
            }
        }
    }

    /**
     * 拣货确认/冲红
     *
     * @param list
     * @param type 0-拣货确认  1-冲红
     */
    @Override
    @Transactional
    @TxTransaction
    @Flow(name = "拣货确认/冲红", category = "出库/拣选单管理/拣货确认、冲红", index = 0, description = "拣货确认/冲红")
    public void pickTaskConfirm(List<PickTaskConfirmVO> list, Integer type) {
        if (list == null || list.size() == 0)
            throw new ParameterException("参数不能为空！");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        String operatorCode = list.get(0).getOperatorCode();
        String warehouseId = list.get(0).getWarehouseId();
        if (StringUtils.isEmpty(operatorCode) || StringUtils.isEmpty(warehouseId))
            throw new ParameterException("参数不能为空！");
        String operatorName = userDTO.getUserBizModel().getEmployeeName();
        String operatorId = userDTO.getId();
        Date date = new Date();
        String locatorId = null; // 盘点库货位id
        List<String> lineIds = new ArrayList<>();
        List<String> taskDIds = new ArrayList<>();
        List<String> redOmsBillIds = new ArrayList<>();
        List<UpdateStockVO> stockVOList = new ArrayList<>();
        List<ReplenishDetailVO> replenishDetailVOList = new ArrayList<>();
        String[] pickTaskDIds = list.stream().map(PickTaskConfirmVO::getPickTaskDId).toArray(String[]::new);
        for (PickTaskConfirmVO vo : list) {
            String pickTaskDId = vo.getPickTaskDId();
            PickTaskD pickTaskD = pickTaskDMapper.findById(pickTaskDId, PickTaskD.class);
            String pickTaskId = pickTaskD.getPickTaskId();
            PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskId, PickTaskH.class);
            if (type == 0) {
                if ("3".equals(pickTaskD.getFlowStatus())) {
                    throw new BizException("拣货已确认！");
                }
                // 拣货确认
                this.pickConfirm(vo, enterpriseId, warehouseId, operatorCode, operatorName, operatorId, date, pickTaskDIds, lineIds, replenishDetailVOList, taskDIds, pickTaskH, pickTaskD);
            } else {
                // 冲红确认
                this.redConfirm(vo, enterpriseId, warehouseId, operatorCode, operatorName, operatorId, date, stockVOList, redOmsBillIds, pickTaskH, pickTaskD);
                // 红冲入盘点库
                if (vo.getMessageType() != null && vo.getMessageType() == 1) {
                    RestMessage<String> rest = warehouseResource.getLocatorIdByCategory("PDK", pickTaskH.getWarehouseId());
                    if (!rest.isSuccess() || rest.getData() == null) {
                        throw new PrologException("查询盘点库货位出错,或货位为空:" + rest.getMessage());
                    }
                    locatorId = rest.getData();
                    // 冲红调整库存
                    updateStock.updateStock(stockVOList, warehouseId, locatorId);
                } else if (vo.getMessageType() != null && vo.getMessageType() == 0) {
                    // 还货回库,如果是部分冲红就不处理(拣货确认时处理);全部冲红才处理
                    if (CollUtil.isNotEmpty(redOmsBillIds)) {
                        // 清除预占
                        List<WaveBillDDO> waveBillDDOs = billDMapper.findByMap(MapUtils.put("billId", pickTaskD.getBillId()).getMap(), WaveBillDDO.class);
                        String[] lineBillIds = waveBillDDOs.stream().map(WaveBillDDO::getId).toArray(String[]::new);
                        InvStockCancelOut stockCancel = new InvStockCancelOut();
                        stockCancel.setLineBillIds(lineBillIds);
                        stockCancel.setOutType("1");
                        log.info("inventoryResource.outCancel，stockCancel={}", JSON.toJSONString(stockCancel));
                        RestMessage restMessage = invClient.outCancel(stockCancel);
                        if (!restMessage.isSuccess()) {
                            log.error("inventoryResource.outCancel，restMessage={}", JSON.toJSONString(restMessage));
                            throw new BizException("扣减库存失败: " + restMessage.getMessage());
                        } else {
                            log.info("inventoryResource.outCancel，restMessage={}", JSON.toJSONString(restMessage));
                        }
                    }
                }
            }
        }
        if (CollUtil.isNotEmpty(lineIds)) {
            // 下架确认,扣减库存
            confirmReplenish.confirmReplenish(lineIds, replenishDetailVOList);
        }
        if (CollUtil.isNotEmpty(redOmsBillIds)) {
            // 整单红冲回传ERP
            this.saveOutcomingRecord(redOmsBillIds);
        }
        // 回传EIS ->异步处理，并增加定时任务扫描未回传以及回传失败的进行从新回传
        ThreadUtil.execAsync(() -> this.sendPickEndToEisByTaskDIds(pickTaskDIds), false);
    }

    /**
     * 拣货完成后回传EIS
     * 根据托盘号查询所有的pick_task_d任务，如果所有的pick_task_d均已完成，则回传EIS
     *
     * @param pickTaskDIds 拣货明细
     */
    public void sendPickEndToEisByTaskDIds(
            String[] pickTaskDIds
    ) {
        log.info("pickTaskD【{}】拣货确认，开始校验是否回传EIS", Arrays.toString(pickTaskDIds));
        if (ArrayUtil.isEmpty(pickTaskDIds)) {
            return;
        }
        List<PickTaskD> pickTaskDList = pickTaskDMapper.findByIds(PickTaskD.class, pickTaskDIds, null);
        if (CollUtil.isEmpty(pickTaskDList)) {
            return;
        }
        // 根据pickTaskDId查询task_out_back，根据task_out_back的托盘号再查询对应pickTaskD是否已经都拣货完成，是则回传EIS
        String[] dIds = pickTaskDList.stream().map(PickTaskD::getObMsgId).toArray(String[]::new);
        Criteria criteria = Criteria.forClass(InfTaskOutBackVO.class);
        Restriction restriction1 = Restrictions.in("msgId", dIds);
        criteria.setRestriction(restriction1);
        List<InfTaskOutBackVO> outBacks = outBackMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(outBacks)) {
            return;
        }
        // 根据托盘号分组
        Map<String, List<InfTaskOutBackVO>> collect = outBacks.stream().collect(Collectors.groupingBy(InfTaskOutBackVO::getContainerNo));
        for (String containerNo : collect.keySet()) {
            this.sendPickEndToEisByContainerNo(containerNo, collect.get(containerNo), pickTaskDIds);
        }
    }

    /**
     * 拣货完成后回传EIS
     * 根据托盘号查询所有的pick_task_d任务，如果所有的pick_task_d均已完成，则回传EIS
     *
     * @param containerNo 托盘号
     */
    private void sendPickEndToEisByContainerNo(
            String containerNo,
            List<InfTaskOutBackVO> outBackVOS,
            String[] pickTaskDIds
    ) {
        List<InfTaskOutBackVO> confirmOutBackVos = new ArrayList<>();
        Criteria criteria = Criteria.forClass(InfTaskOutBackVO.class);
        Restriction restriction1 = Restrictions.eq("containerNo", containerNo);
        Restriction restriction2 = Restrictions.eq("extend03", outBackVOS.get(0).getExtend03());
        criteria.setRestriction(Restrictions.and(restriction1, restriction2));
        List<InfTaskOutBackVO> outBacks = outBackMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(outBacks)) {
            return;
        }
        String[] msgIds = outBacks.stream().map(InfTaskOutBackVO::getMsgId).toArray(String[]::new);
        List<PickTaskD> pickTaskDList = pickTaskDMapper.listPickD4EisConfirm(msgIds);
        if (CollUtil.isEmpty(pickTaskDList)) {
            return;
        }
        PickTaskD pickTaskD = pickTaskDList.stream().filter(var -> new BigDecimal(var.getFlowStatus()).doubleValue() < 3 && ArrayUtil.indexOf(pickTaskDIds, var.getPickTaskDId()) < 0).findFirst().orElse(null);
        // 如果有未拣货确认则不需要回传
        if (null != pickTaskD) {
            log.info("拣货明细id[{}]未确认[{}]，不回传", pickTaskD.getPickTaskDId(), pickTaskD.getFlowStatus());
            return;
        }
        log.info("托盘号[{}]任务已全部完成，开始回传", containerNo);

        // 查询对应locatorId
        Set<String> locatorIds = pickTaskDList.stream().map(PickTaskD::getLocatorId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        if (CollUtil.isNotEmpty(locatorIds)) {
            RestMessage<List<WarehouseLocatorBasicInfo>> locationBasicInfos = warehouseResource.getLocationBasicInfos(locatorIds.toArray(new String[]{}));
            if (locationBasicInfos.isSuccess() && CollUtil.isNotEmpty(locationBasicInfos.getData())) {
                for (InfTaskOutBackVO outBack : outBacks) {
                    PickTaskD pickTaskD1 = pickTaskDList.stream().filter(var -> var.getObMsgId().equals(outBack.getMsgId())).findFirst().orElse(null);
                    if (null == pickTaskD1) {
                        continue;
                    }
                    for (PickTaskD taskD : pickTaskDList) {
                        if (outBack.getMsgId().equals(taskD.getObMsgId())) {
                            WarehouseLocatorBasicInfo locatorBasicInfo = locationBasicInfos.getData().stream().filter(var -> var.getWarehouseLocatorId().equals(taskD.getLocatorId())).findFirst().orElse(null);
                            if (null != locatorBasicInfo) {
                                if (locatorBasicInfo.getWarehouseAreaCategory().equals("AGVZ")) {
                                    outBack.setWmslocationCode("AGVTP01");
                                }
                                if (locatorBasicInfo.getWarehouseAreaCategory().equals("AGVL")) {
                                    outBack.setWmslocationCode("AGVHJ01");
                                }
                                if (locatorBasicInfo.getWarehouseAreaCategory().equals("MJK")) {
                                    outBack.setWmslocationCode("SX01");
                                }
                            }
                        }
                    }
                    confirmOutBackVos.add(outBack);
                }
            }
        }
        this.askIntegrationForPickEnd(confirmOutBackVos);
    }

    private void askIntegrationForPickEnd(List<InfTaskOutBackVO> outBacks) {
        if (CollUtil.isEmpty(outBacks)) {
            return;
        }
        // 对outBacks进行分组 根据billno与containerNo分组
        Map<String, List<InfTaskOutBackVO>> outbackGroup = outBacks.stream().collect(Collectors.groupingBy(InfTaskOutBackVO::getContainerNo));
        ByContainerVo byContainerVo = new ByContainerVo();
        byContainerVo.setContainerCodes(new ArrayList<>(outbackGroup.keySet()));
        byContainerVo.setWarehouseId(outBacks.get(0).getWarehouseId());
        byContainerVo.setEnterprisesId(outBacks.get(0).getEnterpriseId());
        RestMessage<Map<String, List<WmsInvStockQtyVO>>> lotMsg = invClient.listStockLotByContainerCode(byContainerVo);
        for (String key : outbackGroup.keySet()) {
            // 查询托盘库存，如果为0则为空托
            String containerType = "3";
            boolean isAllZero = true;
            String warehouseCategory = "";
            String enterpriseId = "";
            if (lotMsg.isSuccess() && CollUtil.isNotEmpty(lotMsg.getData())) {
                List<WmsInvStockQtyVO> lotList = lotMsg.getData().get(key);
                for (WmsInvStockQtyVO stockQtyVO : lotList) {
                    if (StrUtil.isBlank(enterpriseId)) {
                        enterpriseId = stockQtyVO.getEnterpriseId();
                    }
                    if (isAllZero && stockQtyVO.getQuantity().doubleValue() > 0) {
                        isAllZero = false;
                    }
                    if (StrUtil.isEmpty(warehouseCategory)) {
                        warehouseCategory = stockQtyVO.getWarehouseAreaCategory();
                    }
                }
            }
            if (isAllZero) {
                if (warehouseCategory.equals("MJK")) {
                    containerType = "2";
                }
                if (warehouseCategory.equals("AGVZ")) {
                    containerType = "1";
                }
                // 释放容器
                ContainerQueryVO containerQueryVO = new ContainerQueryVO();
                containerQueryVO.setContainerCode(key);
                containerQueryVO.setEnterpriseId(enterpriseId);
                containerQueryVO.setWarehouseId(byContainerVo.getWarehouseId());
                RestMessage<Object> release = warehouseResource.release(containerQueryVO);
                log.info("托盘库存已经为0，托盘解锁->{},{}", JSONObject.toJSONString(containerQueryVO), JSONObject.toJSONString(release));
            } else {
                containerType = "3";
            }
            ContainerConfirmDto dto = new ContainerConfirmDto();
            dto.setContainerType(containerType);
            dto.setContainerNo(key);
            dto.setSubList(this.castOutBack(outbackGroup.get(key)));
            AskIntegrationVo vo = new AskIntegrationVo();
            vo.setIntegrationCode("confirmContainer");
            vo.setParam(dto);
            log.info("作业完成确认回传EIS参数：{}", JSONObject.toJSONString(vo));
            RestMessage<?> msg = invClient.askIntegration(vo);
            Criteria cr = Criteria.forClass(InfTaskOutBackVO.class);
            Restriction r1 = Restrictions.eq("containerNo", key);
            cr.setRestriction(r1);
            if (msg.isSuccess()) {
                // 更新回传记录表为成功
                outBackMapper.updateMapByCriteria(MapUtils.put("eisFlag", "Y").put("toEisCnt", outbackGroup.get(key).get(0).getToEisCnt() == null ? 1 : outbackGroup.get(key).get(0).getToEisCnt().add(new BigDecimal("1"))).getMap(), cr);
            } else {
                // 更新为失败，并记录错误信息，记录回传次数
                outBackMapper.updateMapByCriteria(MapUtils.put("eisFlag", "E").put("toEisCnt", outbackGroup.get(key).get(0).getToEisCnt() == null ? 1 : outbackGroup.get(key).get(0).getToEisCnt().add(new BigDecimal("1"))).put("EXTEND02", JSONObject.toJSONString(msg)).getMap(), cr);
            }
        }
    }

    private List<EisConfirmSubVo> castOutBack(
            List<InfTaskOutBackVO> outBackVOS
    ) {
        if (CollUtil.isEmpty(outBackVOS)) {
            return new ArrayList<>();
        }
        List<EisConfirmSubVo> subVos = new ArrayList<>();
        for (InfTaskOutBackVO outBackVO : outBackVOS) {
            EisConfirmSubVo subVo = new EisConfirmSubVo();
            subVo.setMsgId(IdUtil.fastSimpleUUID());
            subVo.setTaskId(outBackVO.getTaskId());
            subVo.setSeqNo(outBackVO.getSeqNo());
            subVo.setBusinessType("10");
            subVo.setWorkType("10");
            subVo.setItemId(outBackVO.getItemId());
            subVo.setLotId(outBackVO.getLotId());
            subVo.setOwnerId(outBackVO.getOwnerId());
            subVo.setPackId(outBackVO.getPackId());
            subVo.setWarehouseId(outBackVO.getWarehouseId());
            subVo.setWmslocationCode(outBackVO.getWmslocationCode());
            subVos.add(subVo);
        }
        return subVos;
    }

    /**
     * 定时任务回传EIS
     */
    @Override
    @InterfaceMethod(key = "sendPickEndToEis", name = "定时回传托盘拣货完成至EIS", type = InterfaceType.Send)
    public void sendPickEndToEis() {
        Criteria criteria = Criteria.forClass(InfTaskOutBackVO.class);
        Restriction restriction1 = Restrictions.ne("eisFlag", "Y");
        criteria.setRestriction(restriction1);
        List<InfTaskOutBackVO> outBacks = outBackMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(outBacks)) {
            return;
        }
        this.askIntegrationForPickEnd(outBacks);
    }

    /**
     * 拣选单分页查询
     *
     * @param warehouseId
     * @param status      状态 0：任务索取 1：任务确认
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickOrder> getPickOrderPage(String operatorCode, String bldgId, Integer pickTaskType, String parames, String warehouseId, String status, Integer pageNum, Integer pageSize) {
        if (pickTaskType == null)
            throw new ParameterException("任务类型不能为空");
        PageHelper.startPage(pageNum, pageSize);
        List<PickOrder> list = pickOrderMapper.getPickOrderList(bldgId, pickTaskType, parames, warehouseId, status, operatorCode);
        return PageUtils.getPage(list);
    }

    /**
     * (零货)拣选任务主表查询
     *
     * @param pickOrderId
     * @return
     */
    @Override
    public List<PickTaskH> getPickTaskHList(String pickOrderId) {
        AssertUtils.isNotBlank(pickOrderId, "拣选单id不能为空");
        List<PickTaskH> list = pickTaskHMapper.getTaskHList(pickOrderId);
        return list;
    }

    /**
     * 拣选任务明细分页查询
     *
     * @param pickTaskId
     * @return
     */
    @Override
    public List<PickTaskDDTO> getPickTaskDList(String pickTaskId) {
        List<PickTaskDDTO> list = pickTaskHMapper.getTaskDList(pickTaskId);
        return list;
    }

    /**
     * (零货)拣选确认 分页查询
     *
     * @param pickOrderId
     * @param itemCode
     * @param containerCode
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickTaskDDTO> getPickTaskPage(String pickOrderId, String itemCode, String containerCode, Integer pageNum, Integer pageSize) {
        AssertUtils.isNotBlank(pickOrderId, "拣选单id不能为空");
        PageHelper.startPage(pageNum, pageSize);
        List<PickTaskDDTO> list = pickTaskHMapper.getPickTaskList(pickOrderId, itemCode, containerCode);
        isSupervisePc(list, 11);
        return PageUtils.getPage(list);
    }

    /**
     * 取消拣选单
     *
     * @param pickOrderId
     */
    @Override
    @Transactional
    public void cancelPickOrder(String pickOrderId) {
        AssertUtils.isNotBlank(pickOrderId, "拣选单id不能为空");
        PickOrder pickOrder = pickOrderMapper.findById(pickOrderId, PickOrder.class);
        if (pickOrder != null && !pickOrder.getStatus().equals("0"))
            throw new BizException("该拣选单已确认，无法取消");
        Criteria crt = Criteria.forClass(PickTaskH.class);
        crt.setRestriction(Restrictions.eq("pickOrderId", pickOrderId));
        pickTaskHMapper.updateMapByCriteria(MapUtils.put("status", "0").put("pickOrderId", null).put("stationId", null).put("stationName", null).put("stationCode", null).put("containerCode", null).getMap(), crt);
        pickOrderMapper.deleteById(pickOrderId, PickOrder.class);
    }

    /**
     * 取消拣货任务
     *
     * @param pickTaskId
     */
    @Override
    @Transactional
    public void cancelPickTask(String pickTaskId) {
        AssertUtils.isNotBlank(pickTaskId, "拣选任务id不能为空");
        PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskId, PickTaskH.class);
        if (pickTaskH != null && !StringUtils.isEmpty(pickTaskH.getPickOrderId()))
            throw new BizException("该拣货任务已被索取，无法取消");
        List<PickTaskD> dList = pickTaskDMapper.findByMap(MapUtils.put("pickTaskId", pickTaskId).getMap(), PickTaskD.class);
        if (dList.size() > 0) {
            for (PickTaskD pickTaskD : dList) {
                // 更新库存预占状态
                waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("status", "0").getMap(), WaveStorageDO.class);
            }
        }
        pickTaskDMapper.deleteByMap(MapUtils.put("pickTaskId", pickTaskId).getMap(), PickTaskD.class);
        pickTaskHMapper.deleteById(pickTaskId, PickTaskH.class);
    }

    /**
     * 取消拣货任务批量
     *
     * @param idList idList
     */
    @Override
    @Transactional
    public void cancelPickTask(List<String> idList) {
        if (CollectionUtil.isEmpty(idList)) {
            return;
        }
        for (String pickTaskDId : idList) {
            // 任务未回告前
            Criteria crt = Criteria.forClass(InfTaskOutBackVO.class);
            crt.restrictionBuilder().eq("seqNo", pickTaskDId);
            crt.buildRestriction();
            List<InfTaskOutBackVO> infTaskOutBackVOList = wmsTaskOutBackMapper.findByCriteria(crt);
            if (CollectionUtil.isNotEmpty(infTaskOutBackVOList)) {
                throw new BizException("该拣货任务已回告,无法取消");
            }
            PickTaskD pickTaskD = pickTaskDMapper.findById(pickTaskDId, PickTaskD.class);
            // 更新库存预占状态
            waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("status", "0").getMap(), WaveStorageDO.class);
            pickTaskDMapper.deleteById(pickTaskDId, PickTaskD.class);
            pickTaskHMapper.deleteById(pickTaskD.getPickTaskId(), PickTaskH.class);
        }
    }

    /**
     * 取消订单
     *
     * @param billGroupId
     */
    @Override
    @Transactional
    @TxTransaction
    public void cancelBill(String billGroupId, String warehouseId) {
        AssertUtils.isNotBlank(billGroupId, "订单编号不能为空");
        AssertUtils.isNotBlank(warehouseId, "仓库id不能为空");
        List<BarcodeHDO> list = barcodeHMapper.findByMap(MapUtils.put("billGroupId", billGroupId).put("warehouseId", warehouseId).getMap(), BarcodeHDO.class);
        if (list.size() > 0) {
            if ("5".equals(list.get(0).getCheckStatus())) {
                throw new PrologException("订单已出库完成,无法取消!");
            }
        }

        Criteria crt = Criteria.forClass(WaveBillDO.class);
        crt.restrictionBuilder().eq("billGroupId", billGroupId).eq("warehouseId", warehouseId);
        crt.buildRestriction();
        List<WaveBillDO> billDOList = billMapper.findByCriteria(crt);
        if (billDOList.size() > 0) {
            if (BILL_STATUS.ERP_CANCELED.equals(billDOList.get(0).getStatus()))
                throw new PrologException("该订单已取消,请勿重复操作!");
            billMapper.updateMapByCriteria(MapUtils.put("status", BILL_STATUS.ERP_CANCELED).getMap(), crt);
            pickTaskHMapper.deleteByMap(MapUtils.put("billGroupId", billGroupId).put("warehouseId", warehouseId).put("type", 0).getMap(), PickTaskH.class);
            barcodeHMapper.deleteByMap(MapUtils.put("billGroupId", billGroupId).put("warehouseId", warehouseId).getMap(), BarcodeHDO.class);
            waveMapper.deleteById(billDOList.get(0).getWaveId(), WaveDO.class);
            String[] billIds = billDOList.stream().map(WaveBillDO::getId).toArray(String[]::new);
            Criteria cri = Criteria.forClass(WaveBillDDO.class);
            cri.restrictionBuilder().in("billId", billIds);
            cri.buildRestriction();
            List<WaveBillDDO> waveBillDDOs = billDMapper.findByCriteria(cri);
            String[] lineBillIds = waveBillDDOs.stream().map(WaveBillDDO::getId).toArray(String[]::new);
            if (lineBillIds != null && lineBillIds.length > 0) {
                InvStockCancelOut stockCancel = new InvStockCancelOut();
                stockCancel.setLineBillIds(lineBillIds);
                stockCancel.setOutType("1");
                log.info("invClient.outCancel，stockCancel={}", JSON.toJSONString(stockCancel));
                RestMessage restMessage = invClient.outCancel(stockCancel);
                if (!restMessage.isSuccess()) {
                    log.error("invClient.outCancel，restMessage={}", JSON.toJSONString(restMessage));
                    throw new BizException("扣减库存预占失败: " + restMessage.getMessage());
                }
            }
        }
    }

    /**
     * （整件）拣选任务分页查询
     *
     * @param type         0：任务索取  1：任务确认
     * @param pickOrderId
     * @param itemCode
     * @param operatorCode
     * @param barcode
     * @param srcCode
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickTaskDDTO> getPickTaskAllPage(
            String bldgId,
            String type,
            String pickOrderId,
            String itemCode,
            String operatorCode,
            String barcode,
            String srcCode,
            String warehouseId,
            String billType,
            String containerNo,
            Integer pageNum,
            Integer pageSize
    ) {
        AssertUtils.isNotBlank(type, "类型不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(pageNum, pageSize);
        List<PickTaskDDTO> list = pickTaskHMapper.getPickTaskAllList(
                bldgId,
                type,
                pickOrderId,
                itemCode,
                operatorCode,
                barcode,
                srcCode,
                enterpriseId,
                warehouseId,
                containerNo,
                billType
        );
        if (CollUtil.isEmpty(list)) {
            return new Page<>();
        }
        RestMessage<List<BaseCommonDict>> billTypeList = commonClient.getDictBasicListByCodes("DO_BILL_TYPE", null);
        Map<String, String> billTypes = new HashMap<>();
        billTypeList.getData().forEach(baseCommonDict -> billTypes.put(baseCommonDict.getDictCode(), baseCommonDict.getDictName()));
        for (PickTaskDDTO pickTaskDDTO : list) {
            if (!"Device".equals(pickTaskDDTO.getPickModel())) {
                pickTaskDDTO.setPickModelTypeName("平库任务");
            } else {
                pickTaskDDTO.setPickModelTypeName("立库任务");
            }
            pickTaskDDTO.setUomQty(pickTaskDDTO.getQty().divide(pickTaskDDTO.getConversionRate(), 0, RoundingMode.UP));
            pickTaskDDTO.setPcs(pickTaskDDTO.getUomQty());
            pickTaskDDTO.setBillTypeName(billTypes.get(pickTaskDDTO.getBillType()));
        }
        if (CollUtil.isNotEmpty(list)) {
            // 查询barcoded
            Criteria c1 = Criteria.forClass(BarCodeDDO.class);
            Restriction r1 = Restrictions.in("wmsPickTaskDId", list.stream().map(PickTaskDDTO::getPickTaskDId).toArray());
            c1.setRestriction(r1);
            List<BarCodeDDO> byCriteria = barcodeDMapper.findByCriteria(c1);
            if (CollUtil.isNotEmpty(byCriteria)) {
                for (PickTaskDDTO pickTaskDDTO : list) {
                    String barcodeDIds = byCriteria.stream().filter(var -> var.getWmsPickTaskDId().equals(pickTaskDDTO.getPickTaskDId())).map(BarCodeDDO::getId).collect(Collectors.joining(","));
                    pickTaskDDTO.setWarehouseId(warehouseId);
                    pickTaskDDTO.setBarcode(barcodeDIds);
                }
            }
        }
        isSupervisePc(list, 10);
        return PageUtils.getPage(list);
    }

    private void isSupervisePc(List<? extends IsSuperviseDTO> list, int stage) {
        log.info("isSupervise,list：{},stage：{}", JSON.toJSONString(list), stage);
        if (list == null || list.size() == 0) {
            return;
        }
        try {
            // 阶段：0=入库质检 1=PC拣货 2=PC内复核 3=PC外复核 4=补录 5=PDA拣货 6=PDA内复核 7=PDA外复核
            RestMessage<List<? extends IsSuperviseDTO>> rest = inBoundClient.isSupervise(list, stage);
            if (rest.isSuccess() && rest.getData() != null && rest.getData().size() == list.size()) {
                for (int i = 0; i < rest.getData().size(); i++) {
                    BeanUtils.copyProperties(rest.getData().get(i), list.get(i));
                }
            }
        } catch (Exception e) {
            log.error("调用监管码接口异常", e);
        }
    }

    /**
     * (整件/功能库房/整单)待索取任务 分页查询
     *
     * @param warehouseAreaCode
     * @param itemCode
     * @param srcCode
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickTaskDDTO> getWaitPickTaskPage(
            String bldgId,
            String pickTaskType,
            String warehouseAreaCode,
            String itemCode,
            String srcCode,
            String warehouseId,
            Integer pageNum,
            Integer pageSize,
            String tab,
            String containerCode
    ) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        if (StrUtil.isEmpty(tab) || !tab.equals("1")) {
            tab = "2";
        }
        PageHelper.startPage(pageNum, pageSize);
        List<PickTaskDDTO> list = pickTaskHMapper.getWaitPickTaskList(
                bldgId,
                pickTaskType,
                warehouseAreaCode,
                itemCode,
                srcCode,
                enterpriseId,
                warehouseId,
                tab,
                containerCode
        );
        isSupervisePc(list, 1);
        String typeCode = "";
        if (pickTaskType.equals("4")) {
            // 特殊订单
            typeCode = "special_bill_type";
        } else {
            typeCode = "do_bill_type"; //
        }
        RestMessage<List<BaseCommonDict>> billTypeList = commonClient.getDictBasicListByCodes(typeCode, null);
        Map<String, String> billTypes = new HashMap<>();
        billTypeList.getData().forEach(baseCommonDict -> billTypes.put(baseCommonDict.getDictCode(), baseCommonDict.getDictName()));
        for (PickTaskDDTO pickTaskDDTO : list) {
            if (!"Device".equals(pickTaskDDTO.getPickModel())) {
                pickTaskDDTO.setPickModelTypeName("平库任务");
            } else {
                pickTaskDDTO.setPickModelTypeName("立库任务");
            }
            pickTaskDDTO.setUomQty(pickTaskDDTO.getQty().divide(pickTaskDDTO.getConversionRate(), 0, RoundingMode.UP));
            pickTaskDDTO.setPcs(pickTaskDDTO.getUomQty());
            pickTaskDDTO.setBillTypeName(billTypes.get(pickTaskDDTO.getBillType()));
        }
        return PageUtils.getPage(list);
    }

    /**
     * (功能/整单)任务确认 分页查询
     *
     * @param warehouseId
     * @param pageNum
     * @param pageSize
     * @return
     */
    @Override
    public Page<PickTaskDDTO> getMixPickTaskAllList(
            String bldgId,
            String pickTaskType,
            String pickOrderId,
            String itemCode,
            String operatorCode,
            String srcCode,
            String warehouseId,
            Integer pageNum,
            Integer pageSize
    ) {
        AssertUtils.isNotBlank(operatorCode, "工号不能为空！");
        AssertUtils.isNotBlank(warehouseId, "仓库id不能为空！");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        PageHelper.startPage(pageNum, pageSize);
        List<PickTaskDDTO> list = pickTaskHMapper.getMixPickTaskAllList(
                bldgId,
                pickTaskType,
                pickOrderId,
                itemCode,
                operatorCode,
                srcCode,
                warehouseId,
                enterpriseId
        );
        isSupervisePc(list, 12);
        if (CollUtil.isEmpty(list)) {
            return PageUtils.getPage(list);
        }
        // 查询货主翻译货主名称
        RestMessage<Map<String, BaseCargoOwnerMst>> cargoMstMsg = chainResource.getCargoOwnerByIds(list.stream().map(PickTaskDDTO::getConsignorId).collect(Collectors.toSet()));
        Map<String, BaseCargoOwnerMst> cargoOwnerMstMap = cargoMstMsg.getData();
        // 查询条码
        Map<String, String> barcodes = barcodeDMapper.getBarcodeByPickTaskDId(new ArrayList<>(list.stream().map(PickTaskDDTO::getPickTaskDId).collect(Collectors.toSet())));
        for (PickTaskDDTO pickTaskDDTO : list) {
            pickTaskDDTO.setConsignorName(cargoOwnerMstMap.get(pickTaskDDTO.getConsignorId()).getCargoOwnerName());
            if (barcodes != null) {
                pickTaskDDTO.setBarcode(barcodes.get(pickTaskDDTO.getPickTaskId()) != null ? barcodes.get(pickTaskDDTO.getPickTaskId()) : "");
            }
        }
        return PageUtils.getPage(list);
    }

    /**
     * 查询拣货工作量
     *
     * @param warehouseId
     * @param type        0-整件 1-零货 2-功能库房
     * @return
     */
    @Override
    public PickTaskCountDTO getPickTaskCount(Integer type, String warehouseId) {
        PickTaskCountDTO dto = new PickTaskCountDTO();
        List<Integer> counts = new ArrayList<>();
        List<PickMoveCountDTO> moveList = new ArrayList<>();
        RestMessage<Page<WmsWhBldgDTO>> restMessage = warehouseResource.list(warehouseId, 0, 0);
        if (!restMessage.isSuccess())
            throw new RuntimeException("查询建筑物接口出错" + restMessage.getMessage());
        Page<WmsWhBldgDTO> result = restMessage.getData();
        List<WmsWhBldgDTO> bldgDTOList = result.getList();
        counts = pickTaskHMapper.getPickTaskCount(warehouseId, type);
        moveList = pickTaskHMapper.getPickMoveCount(warehouseId, type);
        if (counts.size() == 2) {
            dto.setPickCount(counts.get(0));
            dto.setMoveCount(counts.get(1));
        }
        List<PickMoveCountDTO> pickMoveCountDTOList = new ArrayList<>();
        Map<String, PickMoveCountDTO> moveMap = null;
        if (moveList.size() > 0 && moveList.get(0).getBldgId() != null) {
            moveMap = moveList.stream().collect(Collectors.toMap(PickMoveCountDTO::getBldgId, a -> a, (key1, key2) -> key1));
        }
        for (WmsWhBldgDTO map : bldgDTOList) {
            PickMoveCountDTO moveCountDTO = new PickMoveCountDTO();
            String bldgId = map.getBldgId();
            String bldgName = map.getBldgName();
            moveCountDTO.setBldgId(bldgId);
            moveCountDTO.setBldgName(bldgName);
            if (moveMap != null && moveMap.containsKey(bldgId)) {
                moveCountDTO.setActiveMoveCount(moveMap.get(bldgId).getActiveMoveCount());
                moveCountDTO.setPassiveMoveCount(moveMap.get(bldgId).getPassiveMoveCount());
            } else {
                moveCountDTO.setActiveMoveCount(0);
                moveCountDTO.setPassiveMoveCount(0);
            }
            pickMoveCountDTOList.add(moveCountDTO);
        }
        dto.setList(pickMoveCountDTOList);
        return dto;
    }

    /**
     * 拣选任务 绑定容器(零货)
     *
     * @param pickOrderId
     * @param containerCode
     */
    @Override
    @Transactional
    public Integer bindContainer(String pickOrderId, String containerCode) {
        AssertUtils.isNotBlank(pickOrderId, "拣选单id不能为空");
        AssertUtils.isNotBlank(containerCode, "容器号不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();

        Criteria crt2 = Criteria.forClass(PickTaskH.class);
        Restriction r4 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction r5 = Restrictions.eq("containerCode", containerCode);
        Restriction r6 = Restrictions.ne("status", "10");
        crt2.setRestriction(Restrictions.and(r4, r5, r6));
        List<PickTaskH> hList = pickTaskHMapper.findByCriteria(crt2);
        Integer count2 = hList.size();
        if (count2 > 0) {
            throw new BizException("绑定的容器已被占用！");
        }

        Criteria crt = Criteria.forClass(PickTaskH.class);
        Restriction r1 = Restrictions.eq("pickOrderId", pickOrderId);
        Restriction r2 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction r3 = Restrictions.isnull("containerCode");
        crt.setRestriction(Restrictions.and(r1, r2, r3));
        crt.setOrder(Order.newInstance().asc("gmtCreate"));
        List<PickTaskH> pickTaskHList = pickTaskHMapper.findByCriteria(crt);
        Integer count = pickTaskHList.size();
        if (count == 0)
            throw new BizException("拣选任务已全部绑定容器！");
        this.isEnableContainerCode(containerCode, pickTaskHList.get(0).getWarehouseId());
        if (count == 1)
            pickOrderMapper.updateMapById(pickTaskHList.get(0).getPickOrderId(), MapUtils.put("status", "1").getMap(), PickOrder.class);
        for (PickTaskH pickTaskH : pickTaskHList) {
            pickTaskH.setContainerCode(containerCode);
            pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("containerCode", containerCode).getMap(), PickTaskH.class);
            break;
        }
        // 容器占用
        this.usedContainer(containerCode, pickTaskHList.get(0).getWarehouseId());
        return count - 1;
    }

    /**
     * 绑定容器-功能库房/整单
     *
     * @param pickOrderId
     * @param containerCode
     * @param bldgId
     * @param warehouseId
     */
    @Transactional
    @Override
    public void bindContainerMix(String pickOrderId, String pickTaskType, String containerCode, String bldgId, String warehouseId) {
        AssertUtils.isNotBlank(pickOrderId, "pickOrderId不能为空");
        AssertUtils.isNotBlank(containerCode, "容器编号不能为空");
        AssertUtils.isNotBlank(bldgId, "建筑物id不能为空");
        AssertUtils.isNotBlank(warehouseId, "仓id不能为空");
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();

        Criteria crt2 = Criteria.forClass(PickTaskH.class);
        Restriction r4 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction r5 = Restrictions.eq("containerCode", containerCode);
        Restriction r6 = Restrictions.ne("status", "10");
        crt2.setRestriction(Restrictions.and(r4, r5, r6));
        List<PickTaskH> hList = pickTaskHMapper.findByCriteria(crt2);
        Integer count2 = hList.size();
        if (count2 > 0) {
            throw new BizException("绑定的容器已被占用！");
        }

        this.isEnableContainerCode(containerCode, warehouseId);
        List<String> list = pickTaskHMapper.getMixPickTaskHIds(pickOrderId, pickTaskType, bldgId, warehouseId, enterpriseId);
        if (list.size() > 0) {
            BaseWmsWhWorkstation workstation = null;
            if ("3".equals(pickTaskType)) {
                workstation = this.getBaseWmsWhWorkstation(null, warehouseId, enterpriseId, containerCode);
            }
            for (String id : list) {
                MapToolKit containerCode1 = MapUtils.put("containerCode", containerCode);
                if (workstation == null) {
                    pickTaskHMapper.updateMapById(id, containerCode1.getMap(), PickTaskH.class);
                } else {
                    pickTaskHMapper.updateMapById(id, containerCode1.put("stationId", workstation.getStationId())
                            .put("stationName", workstation.getStationName())
                            .put("stationCode", workstation.getStationCode()).getMap(), PickTaskH.class);
                }
            }
            PickTaskH h = pickTaskHMapper.findById(list.get(0), PickTaskH.class);
            pickOrderMapper.updateMapById(h.getPickOrderId(), MapUtils.put("status", "1").getMap(), PickOrder.class);
            // 容器占用
            this.usedContainer(containerCode, warehouseId);
        }
    }

    /**
     * 手动下发agv拣货数据
     *
     * @param billGroupIds
     */
    @Transactional
    @Override
    public void manualSendAgv(List<String> billGroupIds) {
        log.info("开始手动下发agv拣货数据!");
        if (billGroupIds.isEmpty())
            throw new PrologException("订单ids不能为空!");
        List<Map<String, Object>> dataList = new ArrayList<>();
        billGroupIds.forEach(billGroupId -> {
            List<PickTaskH> pickTaskHList = pickTaskHMapper.findByMap(MapUtils.put("billGroupId", billGroupId).put("pickTaskType", 1).put("status", "1").put("type", 0).getMap(), PickTaskH.class);
            pickTaskHList.forEach(p -> {
                Map<String, Object> dataMap = pickTaskHMapper.getAgvPickTaskH(p.getPickTaskId(), p.getWarehouseId());
                List<Map<String, Object>> dList = pickTaskHMapper.getAgvPickTaskD(p.getPickTaskId(), p.getWarehouseId());
                dataMap.put("pickTaskD", dList);
                dataList.add(dataMap);
            });
        });
        if (dataList.size() > 0) {
            log.info("下发数据到AGV:" + dataList.toString());
            // 调用接口平台,将拣货任务发送到AGV
            this.askIntegration(sendAgv, MapUtils.put("pickTaskH", dataList).getMap());
        }
        log.info("结束手动下发agv拣货数据!");
    }

    /**
     * 查询AGV拣货明细,生成新的拣货数据
     */
    @Transactional
    @Override
    public void pickTaskConfrim() {
        // 调用接口平台,查询agv已完成拣货的任务明细
        Map<String, Object> dataMap = MapUtils.put("type", "0").getMap();
        JSONObject json = this.askIntegration(sendWms, dataMap);
        JSONArray jsonArray = json.getJSONArray("data");
        log.info("AGV拣货数据:" + jsonArray.toJSONString());
        List<UpdateStockVO> stockVOList = new ArrayList<>();
        List<String> redOmsBillIds = new ArrayList<>();
        List<String> dIds = new ArrayList<>();
        String whId = null;
        if (jsonArray != null && jsonArray.size() > 0) {
            Date date = new Date();
            List<PickTaskD> pickTaskDList = new ArrayList<>();
            PickTaskD oldPickTaskD = null;
            for (int i = 0; i < jsonArray.size(); i++) {
                JSONObject jsonData = jsonArray.getJSONObject(i);
                String pickTaskDId = jsonData.getString("TASK_ID");
                String operatorCode = jsonData.getString("OPERATOR");
                String containerCode = jsonData.getString("CONTAINER_CODE");
                BigDecimal qty = jsonData.getBigDecimal("PLAN_AMOUNT");
                BigDecimal pickQty = jsonData.getBigDecimal("PICKUP_AMOUNT");
                dIds.add(pickTaskDId);
                // 校验AGV的拣货数据
                if (pickTaskDId == null && containerCode == null) {
                    continue;
                } else if (pickTaskDId == null || containerCode == null || qty == null || pickQty == null) {
                    log.error("AGV拣货数据,字段值为空!" + jsonData.toJSONString());
                }
                PickTaskH oldPickTaskH = null;
                if (oldPickTaskD == null || !oldPickTaskD.getPickTaskDId().equals(pickTaskDId)) {
                    oldPickTaskD = pickTaskDMapper.findById(pickTaskDId, PickTaskD.class);
                    if (oldPickTaskD == null) {
                        throw new PrologException("拣货明细不存在,pickTaskDId:" + pickTaskDId);
                    }
                    oldPickTaskH = pickTaskHMapper.findById(oldPickTaskD.getPickTaskId(), PickTaskH.class);
                    pickTaskHMapper.updateMapById(oldPickTaskH.getPickTaskId(), MapUtils.put("status", "2").put("containerCode", containerCode).put("gmtModified", date).getMap(), PickTaskH.class);
                    pickOrderMapper.updateMapById(oldPickTaskH.getPickOrderId(), MapUtils.put("status", "2").put("operatorCode", operatorCode).put("operatorId", operatorCode).put("operatorName", operatorCode).getMap(), PickOrder.class);
                }
                PickTaskD pickTaskD = new PickTaskD();
                BeanUtils.copyProperties(oldPickTaskD, pickTaskD);
                pickTaskD.setQty(qty);
                pickTaskD.setPickQty(pickQty);
                BigDecimal redQty = qty.subtract(pickQty);
                pickTaskD.setSaleRedQty(redQty);
                pickTaskD.setPickerNo(operatorCode);
                pickTaskD.setPickerName(operatorCode);
                pickTaskD.setPickerId(operatorCode);
                pickTaskD.setPickTime(jsonData.getDate("FINISHED_DATE"));
                pickTaskD.setGmtCreate(date);
                pickTaskD.setGmtModified(date);
                pickTaskD.setFlowStatus("3");
                pickTaskDList.add(pickTaskD);
                String warehouseId = oldPickTaskD.getWarehouseId();
                whId = warehouseId;
                String enterpriseId = oldPickTaskD.getEnterpriseId();

                if (redQty.compareTo(BigDecimal.ZERO) > 0) {
                    List<WaveBillDDO> billDDOList = pickTaskHMapper.getBillDList(enterpriseId, warehouseId, pickTaskD.getWaveStorageId());
                    if (billDDOList.size() > 0) {
                        SaleRedRecord saleRedRecord = new SaleRedRecord();
                        saleRedRecord.setQty(redQty);
                        saleRedRecord.setReason("AGV");
                        saleRedRecord.setBillDId(billDDOList.get(0).getId());
                        saleRedRecord.setItemId(billDDOList.get(0).getItemId());
                        saleRedRecord.setSrcCode(billDDOList.get(0).getSrcCode());
                        saleRedRecord.setStatus(0);
                        saleRedRecord.setType(0);
                        saleRedRecord.setPickerId(operatorCode);
                        saleRedRecord.setPickerName(operatorCode);
                        saleRedRecord.setPickerNo(operatorCode);
                        saleRedRecord.setBldgId(oldPickTaskH.getBldgId());
                        saleRedRecord.setWarehouseId(warehouseId);
                        saleRedRecord.setEnterpriseId(enterpriseId);
                        saleRedRecord.setCreator(operatorCode);
                        saleRedRecord.setCreatorName(operatorCode);
                        saleRedRecord.setGmtCreate(date);
                        saleRedRecord.setSrcId(billDDOList.get(0).getSrcId());
                        saleRedRecord.setSrcLineId(billDDOList.get(0).getSrcLineId());
                        saleRedRecordMapper.save(saleRedRecord);
                        // 出库预占调整
                        UpdateStockVO updateStockVO = new UpdateStockVO();
                        updateStockVO.setBillId(billDDOList.get(0).getBillId());
                        updateStockVO.setBillDId(billDDOList.get(0).getId());
                        updateStockVO.setPickTaskDId(pickTaskDId);
                        updateStockVO.setRedQty(redQty);
                        stockVOList.add(updateStockVO);

                        // 如果拣货明细全部红冲
                        if (redQty.compareTo(pickTaskD.getQty()) == 0) {
                            pickTaskDMapper.updateMapById(pickTaskDId, MapUtils.put("flowStatus", "8").getMap(), PickTaskD.class);
                            List<Integer> countList = pickTaskHMapper.getRedCount(billDDOList.get(0).getSrcId(),
                                    billDDOList.get(0).getSrcLineId(), enterpriseId);
                            // 整单红冲则回传erp
                            if (countList.size() > 1 && countList.get(0) == 0 && countList.get(1) == 0) {
                                String billGroupId = oldPickTaskH.getBillGroupId();
                                List<String> omsBillIds = barcodeHMapper.getOmsBillIds(billGroupId, enterpriseId);
                                if (omsBillIds.size() > 0) {
                                    redOmsBillIds.addAll(omsBillIds);
                                }
                                Criteria crt1 = Criteria.forClass(PickTaskH.class);
                                Restriction r1 = Restrictions.eq("billGroupId", billGroupId);
                                Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
                                Restriction r3 = Restrictions.ne("status", "10");
                                crt1.setRestriction(Restrictions.and(r1, r2, r3));
                                pickTaskHMapper.updateMapByCriteria(MapUtils.put("status", "10").getMap(), crt1);
                            }
                        }
                    }
                }
                // 调用接口平台,更新回传状态
                Map<String, Object> map = MapUtils.put("task_id", pickTaskDId).getMap();
                Map<String, Object> paramMap = MapUtils.put("param", map).getMap();
                this.askIntegration(updateAgvStatus, paramMap);
            }
            if (pickTaskDList.size() > 0)
                pickTaskDMapper.saveBatch(pickTaskDList);

            RestMessage<String> rest = warehouseResource.getLocatorIdByCategory("PDK", whId);
            if (!rest.isSuccess() || rest.getData() == null) {
                throw new PrologException("查询盘点库货位出错,或货位为空:" + rest.getMessage());
            }
            this.updateStock(stockVOList, whId, rest.getData());
            // 整单红冲回传ERP
            // 替换方法 by Huanglh 20220112
            // this.saveOutcomingRecord(redOmsBillIds);
            this.saveOutcomingRecordForRed(redOmsBillIds, whId);

            if (dIds.size() > 0) {
                dIds.forEach(x -> {
                    pickTaskDMapper.deleteById(x, PickTaskD.class);
                });
            }
        }
    }

    /**
     * 查询拣货明细,生成新的拣货数据
     */
    @Transactional
    @Override
    public void confirmDevicePickTask(List<ContainerBindTaskDto> containerBindTaskDtoList) {
        // 调用接口平台,查询已完成拣货的任务明细
        List<UpdateStockVO> stockVOList = new ArrayList<>();
        List<String> redOmsBillIds = new ArrayList<>();
        Date date = new Date();
        List<PickTaskD> pickTaskDList = new ArrayList<>();
        log.info("入参为：" + JSON.toJSONString(containerBindTaskDtoList));
        Map<String, PickTaskH> casePickTaskIdMap = new HashMap();
        String whId = "";
        for (int i = 0; i < containerBindTaskDtoList.size(); i++) {
            ContainerBindTaskDto containerBindTaskDto = containerBindTaskDtoList.get(i);
            if (containerBindTaskDto == null || containerBindTaskDto.getOutboundTaskBindDetailList() == null) {
                throw new BizException("入参不合法");
            }
            for (int j = 0; j < containerBindTaskDto.getOutboundTaskBindDetailList().size(); j++) {
                OutboundTaskBindDetail detail = containerBindTaskDto.getOutboundTaskBindDetailList().get(j);
                String pickTaskId = detail.getUpperSystemTaskId();
                String operatorCode = detail.getOperatorCode();
                String containerCode = containerBindTaskDto.getContainerNo();
                BigDecimal qty = detail.getBindingNum();
                BigDecimal pickQty = detail.getBindingNum();
                // 校验AGV的拣货数据
                if (pickTaskId == null && containerCode == null) {
                    continue;
                } else if (pickTaskId == null || containerCode == null || qty == null || pickQty == null) {
                    log.error("Device拣货数据,字段值为空!" + JSON.toJSONString(containerBindTaskDto));
                }
                PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskId, PickTaskH.class);
                if (pickTaskH == null) {
                    throw new BizException("拣货不存在,pickTaskId:" + pickTaskId);
                } else {
                    if (pickTaskH.getType() == 0 && pickTaskH.getPickTaskType() == 0) {
                        casePickTaskIdMap.put(pickTaskH.getPickTaskId(), pickTaskH);
                    }
                    pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("status", "0").
                            put("containerCode", containerCode).put("gmtModified", date).
                            put("remark", containerBindTaskDto.getStationNo()).getMap(), PickTaskH.class);
                }
                Map<String, Object> map = MapUtils.put("billId", pickTaskH.getBillId()).put("itemId", detail.getItemId())
                        .put("batchId", detail.getLotId()).put("type", 0).getMap();
                List<WaveStorageDO> byMap = waveStorageMapper.findByMap(map, WaveStorageDO.class);
                if (byMap == null || byMap.size() != 1) {
                    log.error("找不到对应的库存预占订单,pickTaskId:" + pickTaskId);
                    throw new BizException("找不到对应的库存预占订单");
                }
                String warehouseId = pickTaskH.getWarehouseId();
                whId = warehouseId;
                String enterpriseId = pickTaskH.getEnterpriseId();
                PickTaskD pickTaskD = new PickTaskD();
                pickTaskD.setQty(qty);
                pickTaskD.setPickQty(pickQty);
                BigDecimal redQty = qty.subtract(pickQty);
                pickTaskD.setSaleRedQty(redQty);
                pickTaskD.setPickerNo(operatorCode);
                pickTaskD.setPickerName(operatorCode);
                pickTaskD.setPickerId(operatorCode);
                pickTaskD.setPickTime(DateUtils.parse(detail.getPickTime(), "yyyy-MM-dd HH:mm:ss"));
                pickTaskD.setGmtCreate(date);
                pickTaskD.setGmtModified(date);
                pickTaskD.setPickTaskId(pickTaskId);
                pickTaskD.setWaveStorageId(byMap.get(0).getId());
                pickTaskD.setWarehouseId(warehouseId);
                pickTaskD.setEnterpriseId(enterpriseId);
                pickTaskD.setPickTaskType(0);
                pickTaskD.setPrintCount(0);
                pickTaskD.setFlowStatus("3");
                pickTaskDList.add(pickTaskD);

                if (redQty.compareTo(BigDecimal.ZERO) > 0) {
                    List<WaveBillDDO> billDDOList = pickTaskHMapper.getBillDList(enterpriseId, warehouseId, pickTaskD.getWaveStorageId());
                    if (billDDOList.size() > 0) {
                        SaleRedRecord saleRedRecord = new SaleRedRecord();
                        saleRedRecord.setQty(redQty);
                        saleRedRecord.setReason("Device");
                        saleRedRecord.setBillDId(billDDOList.get(0).getId());
                        saleRedRecord.setItemId(billDDOList.get(0).getItemId());
                        saleRedRecord.setSrcCode(billDDOList.get(0).getSrcCode());
                        saleRedRecord.setStatus(0);
                        saleRedRecord.setType(0);
                        saleRedRecord.setPickerId(operatorCode);
                        saleRedRecord.setPickerName(operatorCode);
                        saleRedRecord.setPickerNo(operatorCode);
                        saleRedRecord.setBldgId(pickTaskH.getBldgId());
                        saleRedRecord.setWarehouseId(warehouseId);
                        saleRedRecord.setEnterpriseId(enterpriseId);
                        saleRedRecord.setCreator(operatorCode);
                        saleRedRecord.setCreatorName(operatorCode);
                        saleRedRecord.setGmtCreate(date);
                        saleRedRecord.setSrcId(billDDOList.get(0).getSrcId());
                        saleRedRecord.setSrcLineId(billDDOList.get(0).getSrcLineId());
                        saleRedRecordMapper.save(saleRedRecord);
                        // 出库预占调整
                        UpdateStockVO updateStockVO = new UpdateStockVO();
                        updateStockVO.setBillId(billDDOList.get(0).getBillId());
                        updateStockVO.setBillDId(billDDOList.get(0).getId());
                        updateStockVO.setPickTaskDId(pickTaskId);
                        updateStockVO.setRedQty(redQty);
                        stockVOList.add(updateStockVO);

                        // 如果拣货明细全部红冲
                        if (redQty.compareTo(pickTaskD.getQty()) == 0) {
                            pickTaskDMapper.updateMapById(pickTaskId, MapUtils.put("flowStatus", "8").getMap(), PickTaskD.class);
                            List<Integer> countList = pickTaskHMapper.getRedCount(billDDOList.get(0).getSrcId(), billDDOList.get(0).getSrcLineId(), enterpriseId);
                            // 整单红冲则回传erp
                            if (countList.size() > 1 && countList.get(0) == 0 && countList.get(1) == 0) {
                                String billGroupId = pickTaskH.getBillGroupId();
                                List<String> omsBillIds = barcodeHMapper.getOmsBillIds(billGroupId, enterpriseId);
                                if (omsBillIds.size() > 0) {
                                    redOmsBillIds.addAll(omsBillIds);
                                }
                                Criteria crt1 = Criteria.forClass(PickTaskH.class);
                                Restriction r1 = Restrictions.eq("billGroupId", billGroupId);
                                Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
                                Restriction r3 = Restrictions.ne("status", "10");
                                crt1.setRestriction(Restrictions.and(r1, r2, r3));
                                pickTaskHMapper.updateMapByCriteria(MapUtils.put("status", "10").getMap(), crt1);
                            }
                        }
                    }
                }
            }
        }
        if (pickTaskDList.size() > 0) {
            Criteria cri = Criteria.forClass(PickTaskD.class);
            cri.restrictionBuilder().in("pickTaskId", casePickTaskIdMap.keySet().toArray());
            cri.buildRestriction();
            pickTaskDMapper.deleteByCriteria(cri);
            pickTaskDMapper.saveBatch(pickTaskDList);
        }
        //this.updateStock(stockVOList,whId);
        //整单红冲回传ERP
        // 替换方法 by Huanglh 20220112
        // this.saveOutcomingRecord(redOmsBillIds);
        this.saveOutcomingRecordForRed(redOmsBillIds, whId);
    }

    /**
     * 查询此补货订单对应的AGV库区零货拣货任务,推送到agv
     *
     * @param itemId
     * @param warehouseId
     */
    @Transactional
    public void sendPickTaskAGV(String itemId, String batchNum, String warehouseId) {
        List<String> pickTaskIds = pickTaskHMapper.getUnPickTaskIds(itemId, batchNum, warehouseId);
        if (pickTaskIds.size() > 0) {
            List<Map<String, Object>> dataList = pickTaskHMapper.getAgvPickTaskHList(pickTaskIds, warehouseId);
            dataList.forEach(h -> {
                List<Map<String, Object>> dList = pickTaskHMapper.getAgvPickTaskD((String) h.get("PICK_TASK_ID"), warehouseId);
                h.put("pickTaskD", dList);
            });
            if (dataList.size() > 0) {
                log.info("查询数据下发到AGV:" + dataList.toString());
                // 调用接口平台,将拣货任务发送到AGV
                this.askIntegration(sendAgv, MapUtils.put("pickTaskH", dataList).getMap());
            }
        }
    }

    @FuncImpl(name = "查询待索取拣货任务", func = OutBoundFunc.getPickTaskHList.class, description = "根据员工作业区域编码查询 wms_pick_task_h表,status为0、pick_task_type为1 的拣货任务")
    public List<PickTaskH> getPickTaskHList(String bldgId, String operatorCode, String warehouseId, String enterpriseId, Map<String, Object> returnMap) {
        // 获取员工作业库区编码集合
        List<String> areaCodes = this.getAreaCodes(operatorCode, warehouseId, "2011", "BULK_PICKING");
        // 任务数
        Integer count = 4;
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"PICK_TASK_NUM"}, warehouseId, null, enterpriseId, bldgId);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> map = restMessage.getData();
            if (map.containsKey("PICK_TASK_NUM"))
                count = Integer.valueOf(map.get("PICK_TASK_NUM").getRegValue());
        }
        List<Integer> pickTaskTypes = new ArrayList<>();
        pickTaskTypes.add(1);
        List<PickTaskH> list = pickTaskHMapper.getPickTaskHList(bldgId, null, enterpriseId, warehouseId, count, pickTaskTypes, areaCodes, null);
        returnMap.put("count", list.size());
        return list;
    }

    @FuncImpl(name = "查询待索取拣货任务", func = OutBoundFunc.getPickTaskHListByBill.class, description = "查询待索取拣货任务")
    public List<PickTaskH> getPickTaskHListByBill(String bldgId, String enterpriseId, String warehouseId, List<String> areaCodes, String type) {
        List<PickTaskH> list = pickTaskHMapper.getPickTaskHListByBill(bldgId, enterpriseId, warehouseId, areaCodes, type);
        return list;
    }

    @FuncImpl(name = "保存批拣单", func = OutBoundFunc.savePickOrder3.class, description = "保存批拣单")
    public void savePickOrder3(String pickOrderId, String operatorId, String operatorCode, String operatorName, String warehouseId, int count, int pickTaskType, int isPrint) {
        PickOrder pickOrder = new PickOrder();
        pickOrder.setPickOrderId(pickOrderId);
        pickOrder.setStatus("0");
        pickOrder.setWarehouseId(warehouseId);
        pickOrder.setTaskCount(count);
        pickOrder.setOperatorId(operatorId);
        pickOrder.setOperatorName(operatorName);
        pickOrder.setOperatorCode(operatorCode);
        pickOrder.setPickTaskType(pickTaskType);
        // 如果自动打印
        if (isPrint == 1) {
            pickOrder.setPrintStatus("1");
        } else {
            pickOrder.setPrintStatus("0");
        }
        ModelUtils.generateBaseData(pickOrder, userTemplate::getUserDTO);
        pickOrderMapper.save(pickOrder);
    }

    public void updatePickTaskD4WholeOrderPick(UserDTO userDTO, String enterpriseId, List<PickTaskH> list) {
        Set billGroupIds = list.stream().map(PickTaskH::getBillGroupId).collect(Collectors.toSet());
        if (list.get(0).getType() == 1) {
            String[] moveBillIds = list.stream().map(PickTaskH::getBillId).toArray(String[]::new);
            Criteria crt = Criteria.forClass(WmsMoveTaskRef.class);
            Restriction r1 = Restrictions.in("moveBillId", moveBillIds);
            crt.setRestriction(Restrictions.and(r1));
            List<WmsMoveTaskRef> wmsMoveTaskRefList = wmsMoveTaskRefMapper.findByCriteria(crt);
            String[] billIds = wmsMoveTaskRefList.stream().map(WmsMoveTaskRef::getBillId).toArray(String[]::new);
            Criteria cr = Criteria.forClass(WaveBillDO.class);
            cr.restrictionBuilder().in("id", billIds).eq("status", BILL_STATUS.WORKSTAGE_FOUND);
            cr.setOrder(Order.newInstance().asc("gmtCreate"));
            cr.buildRestriction();
            List<WaveBillDO> waveBillDOs = billMapper.findByCriteria(cr);
            if (waveBillDOs != null && waveBillDOs.size() > 0) {
                billGroupIds.add(waveBillDOs.get(0).getBillGroupId());
            }
        }
        Criteria crt = Criteria.forClass(PickTaskH.class);
        Restriction r1 = Restrictions.in("billGroupId", billGroupIds.toArray());
        Restriction r2 = Restrictions.eq("enterpriseId", enterpriseId);
        crt.setRestriction(Restrictions.and(r1, r2));
        List<PickTaskH> pickTaskHList = pickTaskHMapper.findByCriteria(crt);
        String[] hIds = pickTaskHList.stream().map(PickTaskH::getPickTaskId).toArray(String[]::new);
        if (hIds != null && hIds.length > 0) {
            // 整单拣选，该订单所有任务都为一个拣货员
            Criteria crt1 = Criteria.forClass(PickTaskD.class);
            Restriction r111 = Restrictions.in("pickTaskId", hIds);
            Restriction r211 = Restrictions.eq("enterpriseId", enterpriseId);
            Restriction r311 = Restrictions.isnull("pickerNo");
            crt1.setRestriction(Restrictions.and(r111, r211, r311));
            pickTaskDMapper.updateMapByCriteria(MapUtils.put("flowStatus", 2).put("pickerId", userDTO.getId())
                    .put("pickerNo", userDTO.getUserBizModel().getEmployeeNo()).put("pickerName", userDTO.getUsername()).getMap(), crt1);
        }
    }

    @FuncImpl(name = "分配复核台", func = OutBoundFunc.getWorkstation.class, description = "根据任务库区找复核台，同订单同库区尽可能放同一个复核台")
    public BaseWmsWhWorkstation getWorkstation(PickTaskH pickTaskH, Map<String, BaseWmsWhWorkstation> stationMap) {
        BaseWmsWhWorkstation workstation = null;
        String areaCode = pickTaskH.getWarehouseAreaCode();
        List<String> stationIds = this.getWorkstationIds(areaCode, pickTaskH.getWarehouseId());
        // 找同订单同库区的复核台
        List<BaseWmsWhWorkstation> stationList = pickTaskHMapper.getStationByBillId(pickTaskH.getPickTaskId(), null, stationIds);
        if (stationList.size() > 0) {
            workstation = stationList.get(0);
            stationMap.put(areaCode, workstation);
        } else if (!stationMap.isEmpty() && stationMap.containsKey(areaCode)) {
            // 找同库区的复核台
            workstation = stationMap.get(areaCode);
        } else {
            workstation = this.getBaseWmsWhWorkstation(areaCode, pickTaskH.getWarehouseId(), pickTaskH.getEnterpriseId());
            stationMap.put(areaCode, workstation);
        }
        return workstation;
    }

    @FuncImpl(name = "更新拣货任务主表", func = OutBoundFunc.updatePickTaskH.class, description = "更新表:wms_pick_task_h,字段:状态(status)=1,复核台相关字段")
    private void updatePickTaskH(PickTaskH pickTaskH, String pickOrderId, BaseWmsWhWorkstation workstation) {
        pickTaskH.setPickOrderId(pickOrderId);
        pickTaskH.setStatus("1");
        pickTaskH.setStationId("-1");
        pickTaskH.setStationName("-1");
        pickTaskH.setStationCode("-1");
        pickTaskHMapper.updateFields(pickTaskH, FieldSelector.newInstance().include(new String[]{"status", "pickOrderId", "stationCode", "stationName", "stationId"}));
    }

    @FuncImpl(name = "保存拣选单", func = OutBoundFunc.savePickOrder.class, description = "拣选单表wms_pick_order新增一条数据")
    public void savePickOrder(String pickOrderId, Employee employee, String warehouseId, int count, int pickTaskType) {
        PickOrder pickOrder = new PickOrder();
        pickOrder.setPickOrderId(pickOrderId);
        pickOrder.setStatus("0");
        pickOrder.setWarehouseId(warehouseId);
        pickOrder.setTaskCount(count);
        pickOrder.setOperatorId(employee.getUserId());
        pickOrder.setOperatorName(employee.getLocname());
        pickOrder.setOperatorCode(employee.getJobnumber());
        pickOrder.setPickTaskType(pickTaskType);
        pickOrder.setPrintStatus("0");
        ModelUtils.generateBaseData(pickOrder, userTemplate::getUserDTO);
        pickOrderMapper.save(pickOrder);
    }

    /**
     * 打印拣货纸单
     *
     * @param pickOrderIds
     * @param warehouseId
     * @param bldgId
     */
    @Flow(name = "打印拣货纸单", category = "出库/拣选单管理/打印", index = 0, description = "支持零货、整散、整件打印")
    @Override
    @Transactional
    public List<PrintData> printPaperSlip(List<String> pickOrderIds, String warehouseId, String bldgId, String pickTaskType) {
        List<PrintData> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        for (String pickOrderId : pickOrderIds) {
            PickOrder pickOrder = pickOrderMapper.findById(pickOrderId, PickOrder.class);
            // 容器绑定改为扫描拣货纸单的时候进行绑定
            List<PickTaskDDTO> list = pickTaskHMapper.getPickTaskDList(pickTaskType, bldgId, pickOrderId, warehouseId);
            if (list.size() > 0) {
                if (pickTaskType.equals("2")) {
                    // 功能库房拣货
                    reportDatas.add(this.order3CreateReportData(list, pickOrder));
                }
                if (pickTaskType.equals("1")) {
                    // 零货拣货
                    reportDatas.add(this.order3CreateReportData(list, pickOrder));
                }
                pickOrderMapper.updateMapById(pickOrderId, MapUtils.put("printStatus", "1").put("printCnt", pickOrder.getPrintCnt() == null ? "1" : pickOrder.getPrintCnt().add(BigDecimal.ONE).toString()).getMap(), PickOrder.class);
            }
        }
        printData.setData(reportDatas);
        printDataList.add(printData);
        return printDataList;
    }

    private ReportData order3CreateReportData(
            List<PickTaskDDTO> list,
            PickOrder pickOrder
    ) {
        Map<String, Object> head = new HashMap<>();
        List<Map<String, Object>> tables = new ArrayList<>();
        ReportData reportData = new ReportData();
        Set<String> itemIds = new HashSet<>();
        BigDecimal totQty = BigDecimal.ZERO;
        BigDecimal totPcs = BigDecimal.ZERO;
        BigDecimal totOdd = BigDecimal.ZERO;
        ItemMstQueryVO vo = new ItemMstQueryVO();
        for (PickTaskDDTO pickTaskDDTO : list) {
            if (StrUtil.isNotEmpty(pickTaskDDTO.getItemId())) {
                itemIds.add(pickTaskDDTO.getItemId());
            }
        }
        vo.setItemIds(itemIds);
        vo.setPageNum(1);
        vo.setPageSize(9999);
        RestMessage<Page<ItemMstVO2>> restMessage = itemClient.pagebyRelated(vo);
        for (PickTaskDDTO pickTaskDDTO : list) {
            Map<String, Object> table = new HashMap<>();
            table.put("locatorCode", pickTaskDDTO.getLocatorCode());
            table.put("itemBar", "");
            if (null != restMessage.getData() && CollUtil.isNotEmpty(restMessage.getData().getList())) {
                for (ItemMstVO2 itemMstVO2 : restMessage.getData().getList()) {
                    if (null != pickTaskDDTO.getItemId() && pickTaskDDTO.getItemId().equals(itemMstVO2.getItemId())) {
                        // 商品条码
                        table.put("itemBar", itemMstVO2.getSpecification());
                    }
                }
            }
            table.put("itemName", pickTaskDDTO.getItemName());
            table.put("itemCode", pickTaskDDTO.getItemCode());
            table.put("pcs", pickTaskDDTO.getUomQty());
            table.put("batchNum", pickTaskDDTO.getBatchNum());
            table.put("manufacturerLotNum", pickTaskDDTO.getManufacturerLotNum());
            table.put("productionDateShow", pickTaskDDTO.getProductionDateShow());
            table.put("expiredDateShow", pickTaskDDTO.getExpiredDateShow());
            table.put("uom", pickTaskDDTO.getUom());
            table.put("warehouseAreaCode", pickTaskDDTO.getWarehouseAreaCode());
            table.put("odd", pickTaskDDTO.getOddPieceQty());
            table.put("qty", pickTaskDDTO.getQty());
            table.put("lotNo", pickTaskDDTO.getManufacturerLotNum());
            table.put("conversionRate", pickTaskDDTO.getConversionRate());
            tables.add(table);
            totQty = totQty.add(pickTaskDDTO.getQty());
            totPcs = totPcs.add(pickTaskDDTO.getUomQty());
            totOdd = totOdd.add(pickTaskDDTO.getOddPieceQty());
        }
        reportData.setTable(tables);
        head.put("containerCode", list.get(0).getContainerCode());
        head.put("consignorCode", list.get(0).getConsignorName());
        head.put("pickerName", pickOrder.getOperatorName());
        head.put("billNo", list.get(0).getBillNo());
        WaveBillDO byId = billMapper.findById(list.get(0).getBillId(), WaveBillDO.class);
        head.put("billGroupId", byId == null ? "" : byId.getBillGroupId());
        head.put("printCnt", null == pickOrder.getPrintCnt() ? 1 : pickOrder.getPrintCnt().intValue());
        head.put("itemCnt", itemIds.size());
        head.put("itemQty", totQty);
        head.put("itemPcs", totPcs);
        head.put("itemOdd", totOdd);
        head.put("shipperCode", list.get(0).getShipperCode());
        head.put("shipperName", list.get(0).getShipperName());
        reportData.setHead(head);
        return reportData;
    }

    @Override
    public List<PrintData> printSpecialPaperSlip(List<String> billIds, String warehouseId, String bldgId, String pickTaskType) {
        List<PrintData> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDataList = new ArrayList<>();
        printData.setPrintName("");
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        int seqCount = 0;
        /*if (CollectionUtil.isNotEmpty(pickTaskDIds)) {
            for (String pickTaskDId : pickTaskDIds) {
                PickTaskD pickTaskD = pickTaskDMapper.findById(pickTaskDId,PickTaskD.class);
                WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(),WaveStorageDO.class);
                WaveBillDO waveBillDO = billMapper.findById(waveStorageDO.getBillId(),WaveBillDO.class);
                WaveBillDDO waveBillDDO = billDMapper.findById(waveStorageDO.getBillDId(),WaveBillDDO.class);
                Map<String, Object> head = new HashMap<>();
                List<Map<String, Object>> tables = new ArrayList<>();
                ReportData reportData = new ReportData();
                Map<String, Object> lineMap = new HashMap<>();
                lineMap.put("seqNo",++seqCount);
                lineMap.put("locatorCode",waveStorageDO.getLocatorCode());
                lineMap.put("itemCode",waveBillDDO.getItemCode());
                lineMap.put("itemName",waveBillDDO.getItemName());
                lineMap.put("itemSpecs",waveBillDDO.getItemSpecs());
                lineMap.put("manufacturer",waveBillDDO.getManufacturer());
                lineMap.put("uom",waveBillDDO.getUom());
                lineMap.put("caseConversionRate",waveBillDDO.getCaseConversionRate());
                lineMap.put("lotNo",waveBillDDO.getManufacturerLotNum());
                lineMap.put("itemQty",waveStorageDO.getQty());
                lineMap.put("itemPcs",waveBillDDO.getTotalPcs());
                BigDecimal[] n = waveStorageDO.getQty().divideAndRemainder(waveBillDDO.getCaseConversionRate());
                lineMap.put("oddPieceQty",n[1]);
                lineMap.put("warehouseAreaCode",waveStorageDO.getWarehouseAreaCode());
                tables.add(lineMap);
                reportData.setTable(tables);
                if (null == head.get("billNo")) {
                    head.put("printCount", pickTaskD.getPrintCount());
                    head.put("shipperCode", waveBillDO.getShipperCode());
                    head.put("billNo", waveBillDO.getSrcCode());//
                    head.put("crustPerson", waveBillDO.getSalesPersonName());
                    head.put("createDate", sdf.format(waveBillDO.getGmtCreate()));
                    head.put("shipperName", waveBillDO.getShipperName());
                    head.put("createBy", waveBillDO.getCreateBy());
                    reportData.setHead(head);
                }
                reportDataList.add(reportData);
                pickTaskDMapper.updateMapById(pickTaskDId, MapUtils.put("flowStatus", "3").put("printCount",pickTaskD.getPrintCount()+1).getMap(), PickTaskD.class);
            }
        }*/
        if (CollectionUtil.isNotEmpty(billIds)) {

            List<PrintParam> printParamList = new ArrayList<>();
            for (String billId : billIds) {
                PrintParam printParam = new PrintParam();
                printParam.setPrintBillCode("tsBill");
                printParam.setParams(MapUtils.put("billId", billId).getMap());
                printParamList.add(printParam);
            }

            log.info("特殊订单批量打印入参：{}", JSON.toJSONString(printParamList));
            List<RestMessage> restMessageList = new ArrayList<>();
            RestMessage<?> restMessage = commonClient.executePrint(printParamList);
            restMessageList.add(restMessage);
            if(!restMessage.isSuccess()) {
                throw new RuntimeException("特殊订单批量打印错误:" + restMessage.getMessage());
            }
            log.info("特殊订单批量打印返回结果：{}", JSON.toJSONString(restMessage));

            /*for (String billId : billIds) {
                List<WaveBillDO> waveBillDOList = billMapper.findByMap(MapUtils.put("srcId", billId).getMap(), WaveBillDO.class);
                if (CollectionUtil.isEmpty(waveBillDOList)) {
                    continue;
                }
                WaveBillDO waveBillDO = waveBillDOList.get(0);
                List<WaveStorageDO> waveStorageDOList = waveStorageMapper.findByMap(MapUtils.put("billId", waveBillDO.getId()).getMap(), WaveStorageDO.class);
                if (CollectionUtil.isEmpty(waveStorageDOList)) {
                    continue;
                }
                for (WaveStorageDO waveStorageDO : waveStorageDOList) {
                    WaveBillDDO waveBillDDO = billDMapper.findById(waveStorageDO.getBillDId(),WaveBillDDO.class);
                    List<PickTaskD> pickTaskDList = pickTaskDMapper.findByMap(MapUtils.put("waveStorageId", waveStorageDO.getId()).getMap(),PickTaskD.class);
                    if (CollectionUtil.isEmpty(pickTaskDList)) {
                        continue;
                    }
                    Map<String, Object> head = new HashMap<>();
                    List<Map<String, Object>> tables = new ArrayList<>();
                    ReportData reportData = new ReportData();
                    for (PickTaskD pickTaskD : pickTaskDList) {
                        Map<String, Object> lineMap = new HashMap<>();
                        lineMap.put("seqNo",++seqCount);
                        lineMap.put("locatorCode",waveStorageDO.getLocatorCode());
                        lineMap.put("itemCode",waveBillDDO.getItemCode());
                        lineMap.put("itemName",waveBillDDO.getItemName());
                        lineMap.put("itemSpecs",waveBillDDO.getItemSpecs());
                        lineMap.put("manufacturer",waveBillDDO.getManufacturer());
                        lineMap.put("uom",waveBillDDO.getUom());
                        lineMap.put("caseConversionRate",waveBillDDO.getCaseConversionRate());
                        lineMap.put("lotNo",waveBillDDO.getManufacturerLotNum());
                        lineMap.put("itemQty",waveStorageDO.getQty());
                        lineMap.put("itemPcs",waveBillDDO.getTotalPcs());
                        BigDecimal[] n = waveStorageDO.getQty().divideAndRemainder(waveBillDDO.getCaseConversionRate());
                        lineMap.put("oddPieceQty",n[1]);
                        lineMap.put("warehouseAreaCode",waveStorageDO.getWarehouseAreaCode());
                        tables.add(lineMap);
                        reportData.setTable(tables);
                        if (null == head.get("billNo")) {
                            head.put("printCount", pickTaskD.getPrintCount());
                            head.put("shipperCode", waveBillDO.getShipperCode());
                            head.put("billNo", waveBillDO.getSrcCode());//
                            head.put("crustPerson", waveBillDO.getSalesPersonName());
                            head.put("createDate", sdf.format(waveBillDO.getGmtCreate()));
                            head.put("shipperName", waveBillDO.getShipperName());
                            head.put("createBy", waveBillDO.getCreateBy());
                            reportData.setHead(head);
                        }
                        reportDataList.add(reportData);
                        pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("flowStatus", "3").put("printCount",pickTaskD.getPrintCount()+1).getMap(), PickTaskD.class);
                    }
                }
            }*/
        }
        printData.setData(reportDataList);
        printDataList.add(printData);
        return printDataList;
    }

    /**
     * 打印整件拣货标签（PDA）
     *
     * @param pickTaskDId
     * @return
     */
    @Override
    @Transactional
    public List<PrintData> printWholeLabel(String pickTaskDId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String enterpriseId = userDTO.getEnterpriseId();
        List<PrintData> printDataList = new ArrayList<>();
        List<String> pickTaskDIds = new ArrayList<>();
        pickTaskDIds.add(pickTaskDId);
        List<Map<String, Object>> list = this.getWholeLabelData(pickTaskDIds, null, null, enterpriseId);
        if (list.size() > 0) {
            Map<String, Object> map = list.get(0);
            // 走电梯还是输送线,现在不要了
            map.put("KHBZ", "正常");
            List<ReportData> reportDatas = new ArrayList<>();
            ReportData reportData = new ReportData();
            reportData.setHead(map);
            reportDatas.add(reportData);
            PrintData printData = new PrintData();
            printData.setData(reportDatas);
            printData.setPrintName("");
            printDataList.add(printData);
            pickOrderMapper.updateMapById(map.get("PICKORDERID"), MapUtils.put("printStatus", "1").getMap(), PickOrder.class);
            return printDataList;
        }
        return null;
    }

    /**
     * 打印整件拣货标签
     *
     * @param pickTaskDIds
     * @param warehouseId
     * @param type         0-拣货任务 1-补货任务
     * @return
     */
    @Override
    @Transactional
    public List<PrintDataWithMark> printWholeLabels(
            List<String> pickTaskDIds,
            List<String> barcodeIds,
            String warehouseId,
            Integer type,
            String operatorName
    ) {
        return this.printWholeLabels(pickTaskDIds, barcodeIds, warehouseId, type, operatorName, null);
    }

    /**
     * 打印整件拣货标签
     *
     * @param pickTaskDIds
     * @param warehouseId
     * @param type         0-拣货任务 1-补货任务
     * @return
     */
    @Transactional
    public List<PrintDataWithMark> printWholeLabels(
            List<String> pickTaskDIds,
            List<String> barcodeIds,
            String warehouseId,
            Integer type,
            String operatorName,
            String enterpriseId
    ) {
        if (pickTaskDIds == null || pickTaskDIds.size() == 0)
            throw new PrologException("ids不能为空！");
        if (type == null)
            throw new PrologException("类型不能为空！");
        if (StrUtil.isEmpty(enterpriseId)) {
            UserDTO userDTO = userTemplate.getUserDTO();
            enterpriseId = userDTO.getEnterpriseId();
        }
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        List<Map<String, Object>> maps;
        // 拣货标签
        if (type == 0) {
            maps = this.getWholeLabelData(pickTaskDIds, barcodeIds, warehouseId, enterpriseId);
            // 补货标签
        } else {
            maps = pickTaskHMapper.getWholeMoveLabel(pickTaskDIds, warehouseId, enterpriseId);
        }
        Set<String> dids = new HashSet<>();
        if (maps != null && maps.size() > 0) {
            Set<String> itemIds = maps.stream().map(var -> (String) var.get("itemId")).collect(Collectors.toSet());
            RestMessage<List<BaseMtlItemMst>> itemMsg = itemClient.getListByIds(itemIds);
            for (Map<String, Object> map : maps) {
                Map<String, Object> head = new HashMap<>();
                // 公共字段
                BaseMtlItemMst itemInfoVO = itemMsg.getData().stream().filter(var -> var.getItemId().equals(map.get("itemId"))).findFirst().orElse(null);
                head.put("conversionRate", null == itemInfoVO ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() == null ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() + itemInfoVO.getCaseUom());
                dids.add((String) map.get("BQ"));
                head.put("itemName", map.get("SPMCH")); // 商品名称
                head.put("barcode", map.get("id")); // 条码/二维码==>barcode_d的id
                head.put("box", map.get("container_code")); // 箱号/数量
                head.put("itemCode", map.get("itemcode") == null ? map.get("SPBH") : map.get("itemcode")); // 商品code
                head.put("manufacturer", map.get("SHENGCCJ")); // 生产厂家
                head.put("qty", map.get("Z_QTY")); // 明细数量
                head.put("packUnits", map.get("SHPGG")); // 商品规格
                head.put("uom", map.get("DW")); // 单位
                head.put("remark", map.get("REMARK")); // 备注
                head.put("lotNo", map.get("PH")); // 批号
                head.put("productionDate", map.get("P_DATE_S")); // 生产日期
                head.put("expiredDate", map.get("E_DATE_S")); // 有效期至
                head.put("CPH", ((BigDecimal) map.get("print_cnt")).compareTo(BigDecimal.ZERO) > 0 ? "重" : "");
                if (type == 1) {
                    // 补货标签特有
                    if (map.get("MOVETYPE") != null) {
                        switch ((String) map.get("MOVETYPE")) {
                            case "1":
                                head.put("taskType", "主动补货");
                                break;
                            case "2":
                                head.put("taskType", "紧急补货");
                                break;
                            case "3":
                                head.put("taskType", "波次补货");
                                break;
                            case "4":
                                head.put("taskType", "被动补货");
                                break;
                            default:
                                head.put("taskType", "");
                        }
                        head.put("pzwh", itemInfoVO.getBaseMtlItemHealth().getItemHealthApprovalNbr());
                        head.put("picker", map.get("CZR") == null ? userTemplate.getUserDTO().getNickname() : map.get("CZR"));
                        head.put("billDate", map.get("gmt_create") == null ? DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_PATTERN) : DateUtil.format((Date) map.get("gmt_create"), DatePattern.PURE_DATE_PATTERN));
                        head.put("srcLocator", map.get("XSHW"));
                        head.put("destLocator", map.get("KB"));
                        head.put("destAreaCode", map.get("destAreaCode"));
                        head.put("billId", map.get("DJBHQ"));
                    } else {
                        head.put("taskType", "补货");
                    }
                } else {
                    // 拣货标签特有
                    head.put("zcq", map.get("ZCQQSH")); // 暂存编号
                    head.put("psfx", map.get("PSFX")); // 配送方向
                    head.put("billid", map.get("billid")); // 订单id
                    head.put("locatorCode", map.get("LOCATOR_CODE")); // 货位
                    head.put("checkName", map.get("FHR1") == null ? userTemplate.getUserDTO().getNickname() : map.get("FHR1"));//拣货员
                    head.put("kpy", map.get("YWY"));
                    head.put("receiveAddress", map.get("DW_DZ"));
                    head.put("lxr", map.get("lxr"));
                    head.put("tel", map.get("lxfs"));
                    head.put("shipperCode", map.get("shipperCode"));
                    head.put("shipperName", map.get("shipperName"));
                }
                ReportData reportData = new ReportData();
                reportData.setHead(head);
                reportDatas.add(reportData);
                barcodeDMapper.updateMapById(map.get("id"), MapUtils.put("printCnt", ((BigDecimal) map.get("print_cnt")).intValue() + 1).getMap(), BarCodeDDO.class);
                if (map.get("PRINTSTATUS") != null && map.get("PRINTSTATUS").equals("0")) {
                    pickOrderMapper.updateMapById(map.get("PICKORDERID"), MapUtils.put("printStatus", "1").getMap(), PickOrder.class);
                }
            }
            if (barcodeIds != null && barcodeIds.size() > 0) {
                for (int i = 0; i < barcodeIds.size(); i++) {
                    barcodeHMapper.updateMapById(barcodeIds.get(i), MapUtils.put("status", "1").getMap(), BarcodeHDO.class);
                }
            }
        }
        if (CollUtil.isNotEmpty(dids)) {
            pickTaskDMapper.updatePrintCount(new ArrayList<>(dids));
        }
        printData.setData(reportDatas);
        printDataList.add(new PrintDataWithMark(printData, null != type ? type + "" : "1"));
        return printDataList;
    }

    /**
     * 查询整件拣货标签数据
     *
     * @param pickTaskDIds
     * @param warehouseId
     * @param enterpriseId
     * @return
     */
    private List<Map<String, Object>> getWholeLabelData(
            List<String> pickTaskDIds,
            List<String> barcodeIds,
            String warehouseId,
            String enterpriseId
    ) {
        List<Map<String, Object>> list = pickTaskHMapper.getWholeLabel(pickTaskDIds, barcodeIds, warehouseId, enterpriseId);
        // 查询商品信息 取包装单位(最小包装)，包装数量(包装数量)，单位(中包装)；即 xx(包装数量)盒(最小包装单位)/箱(中包装)
        if (list.size() > 0) {
            List<Map<String, Object>> result = new ArrayList<>();
            for (Map<String, Object> map : list) {
                String workStageCodes = getStage((String) map.get("DJBHQ"));
                if (workStageCodes != null) {
                    map.put("ZCQQSH", workStageCodes);
                } else {
                    map.put("ZCQQSH", "机动");
                }
                if (((BigDecimal) map.get("print_cnt")).compareTo(BigDecimal.ZERO) > 0) {
                    map.put("CPH", "重"); // 重打标志，例:   重
                } else {
                    map.put("CPH", "");
                }
                map.putIfAbsent("LXFS", "");
                map.putIfAbsent("P_DATE_S", "");
                map.putIfAbsent("E_DATE_S", "");
                map.putIfAbsent("BM", "");
                result.add(map);
            }
            return result;
        }
        return null;
    }

    private String getStage(String srcCode) {
        List<WorkStageRuntimeDO> workStages = workStageRuntimeMapper.findByMap(MapUtils.put("billGroupId", srcCode).getMap(),
                WorkStageRuntimeDO.class);
        return workStages.stream().
                map(WorkStageRuntimeDO::getStageCode).
                filter(s -> !StringUtils.isBlank(s)).
                distinct().
                collect(Collectors.joining(","));
    }

    @Override
    public BaseWmsWhWorkstation getBaseWmsWhWorkstation(String areaCode, String warehouseId, String enterpriseId) {
        return getBaseWmsWhWorkstation(areaCode, warehouseId, enterpriseId, null);
    }

    /*
     找复核台规则：
      1 找同订单的任务的复核台
      2 查询任务明细的库位集合
      3 根据库位集合查询对应的复核台集合
      4 查询任务最少的复核台
    */
    public BaseWmsWhWorkstation getBaseWmsWhWorkstation(String areaCode, String warehouseId, String enterpriseId, String containerCode) {
        BaseWmsWhWorkstation workstation = null;

        // 根据库区查询对应工作站列表
        List<String> codes = new ArrayList<>();
        codes.add(areaCode);
        Map map = new HashMap();
        map.put("warehouseId", warehouseId);
        if (areaCode != null)
            map.put("areaCodes", codes);
        if (!StringUtils.isBlank(containerCode)) {
            map.put("containerCode", containerCode);
        }

        RestMessage<List<BaseWmsWhWorkstation>> rest = warehouseResource.getWorkstationListByAreaCode(map);
        if (!rest.isSuccess())
            throw new RuntimeException("查询工作站失败！" + rest.getMessage() + "areaCode :" + codes.toString());
        List<BaseWmsWhWorkstation> stationList = rest.getData();
        if (stationList != null && stationList.size() > 0) {
            List<String> stationIds = stationList.stream().map(BaseWmsWhWorkstation::getStationId).collect(Collectors.toList());
            //查询有工作任务的复核台
            List<BaseWmsWhWorkstation> workList = pickTaskHMapper.getStationOfWorks(stationIds, enterpriseId, warehouseId);
            workList = workList.stream().filter(Objects::nonNull).collect(Collectors.toList());
            if (workList.size() == stationList.size()) {
                workstation = workList.get(0);
            } else if (workList.size() == 0) {
                workstation = stationList.get(0);
            } else {
                List<BaseWmsWhWorkstation> finalList = workList;
                List<BaseWmsWhWorkstation> differenceList = stationList.stream().filter(item -> !finalList.stream().map(e -> e.getStationId()).collect(Collectors.toList()).contains(item.getStationId())).collect(Collectors.toList());
                workstation = differenceList.get(0);
            }
        } else {
            if (StringUtils.isBlank(containerCode)) {
                workstation = new BaseWmsWhWorkstation();
                workstation.setStationId("-1");
                workstation.setStationName("-1");
                workstation.setStationCode("-1");
            }
        }
        return workstation;
    }

    public List<String> getWorkstationIds(String areaCode, String warehouseId) {
        List<String> codes = new ArrayList<>();
        codes.add(areaCode);
        Map map = new HashMap();
        map.put("warehouseId", warehouseId);
        if (areaCode != null)
            map.put("areaCodes", codes);
        RestMessage<List<BaseWmsWhWorkstation>> rest = warehouseResource.getWorkstationListByAreaCode(map);
        if (!rest.isSuccess())
            throw new RuntimeException("查询工作站失败！" + rest.getMessage() + "areaCode :" + codes.toString());
        List<BaseWmsWhWorkstation> stationList = rest.getData();
        if (stationList != null && stationList.size() > 0) {
            List<String> stationIds = stationList.stream().map(BaseWmsWhWorkstation::getStationId).collect(Collectors.toList());
            return stationIds;
        } else {
            return null;
        }
    }

    /**
     * 容器占用
     *
     * @param containerCode
     */
    public void usedContainer(String containerCode, String warehouseId) {
        ContainerQueryVO queryVO = new ContainerQueryVO();
        queryVO.setWarehouseId(warehouseId);
        queryVO.setContainerCode(containerCode);
        RestMessage<Object> restMessage = warehouseResource.used(queryVO);
        if (!restMessage.isSuccess())
            throw new PrologException("容器占用接口调用失败！" + restMessage.getMessage());
        boolean isEnable = (boolean) restMessage.getData();
        if (!isEnable)
            throw new PrologException("容器占用失败！" + restMessage.getMessage());
    }

    /**
     * 校验容器编号是否存在/可用
     *
     * @param containerCode
     * @param warehouseId
     */
    public void isEnableContainerCode(String containerCode, String warehouseId) {
        ContainerQueryVO queryVO = new ContainerQueryVO();
        queryVO.setWarehouseId(warehouseId);
        queryVO.setContainerCode(containerCode);
        RestMessage<Boolean> restMessage = warehouseResource.isEnable(queryVO);
        if (!restMessage.isSuccess()) {
            throw new PrologException("查询容器是否可用失败！" + restMessage.getMessage());
        }
        boolean isEnable = restMessage.getData();
        if (!isEnable) {
            throw new PrologException("容器编号不正确或已被占用！");
        }
    }

    // 获取员工作业库区编码集合
    @FuncImpl(name = "获取员工作业库区编码集合", func = OutBoundFunc.getAreaCodes.class, description = "根据工号/仓库id/业务类型/作业类型查询员工作业库区编码集合")
    public List<String> getAreaCodes(String operatorCode, String warehouseId, String businesstype, String worktype) {
        RestMessage<List<String>> restMessage1 = controlResource.getWorkareaList(operatorCode, warehouseId, businesstype, worktype, null);
        if (!restMessage1.isSuccess())
            throw new RuntimeException("获取员工作业库区编码集合失败！" + restMessage1.getMessage());
        List<String> areaCodes = restMessage1.getData();
        if (areaCodes == null || areaCodes.size() == 0)
            throw new BizException("该员工未配置，整件拣货/补货作业区域权限！");
        return areaCodes;
    }

    //获取员工编码集合
    @Override
    public List<String> getOperatorList(String workarea, String businesstype, String type, String enterpriseId, String warehouseId) {
        RestMessage<List<String>> restMessage1 = controlResource.getOperatorList(workarea, businesstype, type, enterpriseId, warehouseId);
        if (!restMessage1.isSuccess())
            throw new RuntimeException("获取员工编码集合失败！" + restMessage1.getMessage());
        List<String> areaCodes = restMessage1.getData();
        if (areaCodes == null || areaCodes.size() == 0)
            throw new BizException("未找到员工编码数据！");
        return areaCodes;
    }

    @Override
    @InterfaceMethod(key = "sendDeviceTaskList", name = "AGV任务推送", type = InterfaceType.Send)
    public RestMessage<?> sendDeviceTaskList(List<InfTaskOutVO> list) {
        if (CollectionUtil.isNotEmpty(list)) {
            // 调用EIS接口,发送任务
            RestMessage<?> rest = eisOutboundClient.outBoundRequest(list);
            if (null == rest || !rest.isSuccess()) {
                log.info("下发任务到EIS失败" + rest.getMessage());
                return new RestMessage(false, "500", "重新推送出库任务失败", rest.getData());
            } else {
                List<InfTaskOutVO> result = new ArrayList<>();
                JSONArray jsonArray = JSONArray.parseArray(JSON.toJSONString(rest.getData()));
                List<InfTaskOutVO> rsList = jsonArray.toJavaList(InfTaskOutVO.class);
                rsList.forEach(vo -> {
                    InfTaskOutVO byId = wmsTaskOutMapper.findById(vo.getMsgId(), InfTaskOutVO.class);
                    if (null == byId) {
                        vo.setWmFlg("Y"); // 设置为失败
                        result.add(vo);
                    }
                });
                if (result.size() > 0) {
                    wmsTaskOutMapper.saveBatch(result);
                }
            }
            // 下发成功,修改表状态为成功；
            list.forEach(vo -> {
                wmsTaskOutMapper.updateMapById(vo.getMsgId(), MapUtils.put("wmFlg", "Y").getMap(), InfTaskOutVO.class);
            });
            return new RestMessage(true, "200", "重新推送出库任务成功", "");
        } else {
            return new RestMessage(false, "500", "入参为空", "");
        }
    }

    @Override
    @InterfaceMethod(key = "reSendDeviceTaskList", name = "重新推送失败的AGV任务-定时任务", type = InterfaceType.Send)
    public RestMessage<?> reSendDeviceTaskList() {
        // 查询发送失败的记录
        Criteria cr = Criteria.forClass(InfTaskOutVO.class);
        cr.restrictionBuilder().eq("wmFlg", "N");
        cr.buildRestriction();
        List<InfTaskOutVO> infTaskOutVOS = wmsTaskOutMapper.findByCriteria(cr);
        if (CollectionUtil.isNotEmpty(infTaskOutVOS)) {
            // 调用接口平台推送EIS
            try {
                if (StringUtils.isEmpty(infTaskOutUrl)) {
                    throw new BizException("请求路径配置为空");
                }
                String url = infTaskOutUrl;
                log.info("调用EIS接口URL:{}", JSONUtil.toJsonStr(url));
                log.info("调用EIS接口参数:{}", JSONUtil.toJsonStr(infTaskOutVOS));
                String result = HttpUtil.post(url, JSONObject.toJSONString(infTaskOutVOS));
                JSONObject json = JSONObject.parseObject(result);
                if (json.containsKey("success") && !json.getBoolean("success")) {
                    log.info("下发任务到EIS失败");
                    infTaskOutVOS.forEach(vo -> {
                        vo.setWmFlg("N"); // 设置为失败
                        vo.setExtend02("下发任务到EIS失败,失败原因为:" + json);
                    });
                    return new RestMessage(false, "500", "重新推送出库任务失败", infTaskOutVOS);
                }
                // 下发成功,修改表状态为成功；
                infTaskOutVOS.forEach(vo -> {
                    wmsTaskOutMapper.updateMapById(vo.getMsgId(), MapUtils.put("wmFlg", "Y").getMap(), InfTaskOutVO.class);
                });
                return new RestMessage(true, "200", "重新推送出库任务成功", "");
            } catch (Exception e) {
                log.info("下发任务到EIS失败");
                String subErrorMsg = "";
                if (!StringUtils.isBlank(e.getMessage())) {
                    subErrorMsg = e.getMessage().length() > 500 ? e.getMessage().substring(0, 500) : e.getMessage();
                }
                String finalSubErrorMsg = subErrorMsg;
                infTaskOutVOS.forEach(vo -> {
                    vo.setWmFlg("N"); // 设置为失败
                    vo.setExtend02("下发任务到EIS失败,失败原因为:" + finalSubErrorMsg);
                });
                return new RestMessage(false, "500", "重新推送出库任务失败", infTaskOutVOS);
            }
        } else {
            return new RestMessage(false, "500", "入参为空", "");
        }
    }

    @Override
    public List<OutcomingRecordHDto> queryOutboundDataToOms(List<String> omsBillIds) {
        List<OutcomingRecordHDto> rsList = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        log.info("omsBillIds参数为:{}", JSONUtil.toJsonStr(omsBillIds));
        if (CollectionUtil.isNotEmpty(omsBillIds)) {
            for (String billId : omsBillIds) {
                // 查询未发送过的记录
                Criteria crt = Criteria.forClass(OutcomingRecordH.class);
                Restriction r1 = Restrictions.eq("billid", billId);
                crt.setRestriction(Restrictions.and(r1));
                List<OutcomingRecordH> outcomingRecordHList = outcomingRecordHMapper.findByCriteria(crt);
                if (CollectionUtil.isNotEmpty(outcomingRecordHList)) {
                    // 循环处理数据
                    OutcomingRecordHDto outcomingRecordHDto = null;
                    for (OutcomingRecordH recordH : outcomingRecordHList) {
                        outcomingRecordHDto = new OutcomingRecordHDto();
                        outcomingRecordHDto.setSaleOrderId(recordH.getBillid());
                        outcomingRecordHDto.setBranchid(recordH.getBranchid());
                        outcomingRecordHDto.setBranchcode(recordH.getBranchcode());
                        outcomingRecordHDto.setBillno(recordH.getBillno());
                        if (null != recordH.getCreatedate()) {
                            outcomingRecordHDto.setBilldate(sdf.format(recordH.getCreatedate()));
                        }
                        outcomingRecordHDto.setCompanyCode(recordH.getShippercode());
                        outcomingRecordHDto.setSalespersonId(recordH.getSalespersonId());
                        outcomingRecordHDto.setPickUp(recordH.getArrivalMode());
                        if (null != recordH.getBillOutTime()) {
                            outcomingRecordHDto.setPickDate(sdf.format(recordH.getBillOutTime()));
                        }
                        outcomingRecordHDto.setBillType(recordH.getBilltype());
                        outcomingRecordHDto.setConsignorcode(recordH.getConsignorcode());
                        outcomingRecordHDto.setConsignorname(recordH.getConsignorname());
                        outcomingRecordHDto.setCarrierName(recordH.getCarrierName());
                        outcomingRecordHDto.setCarrierCode(recordH.getCarrierId());
                        outcomingRecordHDto.setShipbillNo(recordH.getShilineId());
                        outcomingRecordHDto.setPenterpriseid(recordH.getEnterpriseid());
                        outcomingRecordHDto.setStagareadescrip(StringUtils.isEmpty(recordH.getStageCodeMax()) ? recordH.getStageCodeMin() : recordH.getStageCodeMax());
                        // 通过billId查询得到明细行;
                        Criteria cr1 = Criteria.forClass(OutcomingRecordD.class);
                        cr1.restrictionBuilder().eq("billid", recordH.getBillid());
                        cr1.buildRestriction();
                        List<OutcomingRecordD> outcomingRecordDList = outcomingRecordDMapper.findByCriteria(cr1);
                        OutcomingRecordDDto outcomingRecordDDto = null;
                        List<OutcomingRecordDDto> lineList = new ArrayList<>();
                        if (CollectionUtil.isNotEmpty(outcomingRecordDList)) {
                            for (OutcomingRecordD recordD : outcomingRecordDList) {
                                outcomingRecordDDto = new OutcomingRecordDDto();
                                outcomingRecordDDto.setLineId(String.valueOf(SnowFlakeUtils.getId()));
                                outcomingRecordDDto.setBillno(recordD.getBillno());
                                outcomingRecordDDto.setRefSeqNo(recordD.getSeqno());
                                outcomingRecordDDto.setItemId(recordD.getItemid());
                                outcomingRecordDDto.setItemcode(recordD.getItemcode());
                                if (null != recordD.getAffirmedQty()) {
                                    outcomingRecordDDto.setQty(recordD.getAffirmedQty());
                                } else {
                                    outcomingRecordDDto.setQty(BigDecimal.ZERO);
                                }
                                outcomingRecordDDto.setPcs(recordD.getAffirmedPcs());
                                if (null != recordD.getAffirmedOdd()) {
                                    outcomingRecordDDto.setOdd(recordD.getAffirmedOdd());
                                } else {
                                    outcomingRecordDDto.setOdd(BigDecimal.ZERO);
                                }
                                outcomingRecordDDto.setLotNo(recordD.getLotNo());
                                outcomingRecordDDto.setProduceCode(recordD.getBatchNo());
                                outcomingRecordDDto.setPdateFrom(recordD.getPdateFrom());
                                outcomingRecordDDto.setValidUntil(recordD.getValidUntil());
                                outcomingRecordDDto.setConsignorcode(recordD.getConsignorcode());
                                outcomingRecordDDto.setExterreviewer(recordD.getExterreviewer());
                                outcomingRecordDDto.setExterreviewer2(recordD.getExterreviewer2());
                                outcomingRecordDDto.setSorter(recordD.getSorter());
                                outcomingRecordDDto.setSorter2(recordD.getSorter());
                                if (null != recordH.getCheckdate()) {
                                    outcomingRecordDDto.setReviewerDate(sdf.format(recordH.getCheckdate()));
                                }
                                if (null != recordD.getAffirmedQty()) {
                                    if (recordD.getAffirmedQty().compareTo(BigDecimal.ZERO) > 0) {
                                        outcomingRecordDDto.setActQty(String.valueOf(recordD.getAffirmedQty()));
                                    } else {
                                        outcomingRecordDDto.setActQty("0");
                                    }
                                }
                                outcomingRecordDDto.setItemStatus("");
                                outcomingRecordDDto.setSterilizationDate(sdf.format(new Date()));
                                outcomingRecordDDto.setSterilizationLotNo("");
                                outcomingRecordDDto.setPenterpriseid(recordD.getEnterpriseid());
                                outcomingRecordDDto.setSumboxnum(recordD.getSumboxnum());
                                outcomingRecordDDto.setRushrednumb(recordD.getRushrednumb());
                                outcomingRecordDDto.setRushredreason(recordD.getRushredreason());
                                lineList.add(outcomingRecordDDto);
                            }
                        }
                        outcomingRecordHDto.setOutcomingRecordDDtoList(lineList);
                        rsList.add(outcomingRecordHDto);
                    }
                }
            }
        }
        log.info("返回出库记录:{}", JSONUtil.toJsonStr(rsList));
        return rsList;
    }

    @Override
    @FuncImpl(name = "冲红调整库存", func = OutBoundFunc.updateStock.class, description = "冲红调整库存")
    public void updateStock(List<UpdateStockVO> stockVOList, String warehouseId, String locatorId) {
        if (stockVOList.size() > 0) {
            ValidList<InvStockOut> validList = new ValidList<>();
            List<WmsAdjustAddVO> adjustAddVOList = new ArrayList<>();
            for (UpdateStockVO vo : stockVOList) {
                InvStockOut invStockOut = new InvStockOut();
                List<InvStockOutDetail> details = new ArrayList<>();
                InvStockOutDetail detail = new InvStockOutDetail();
                details.add(detail);
                invStockOut.setDetails(details);
                invStockOut.setBillId(vo.getBillId());
                invStockOut.setLineBillId(vo.getBillDId());
                invStockOut.setWarehouseId(warehouseId);
                List<WaveStorageDO> storageDOS = waveStorageMapper.getStorageByPickTaskDId(vo.getPickTaskDId());
                if (storageDOS.size() != 1) {
                    throw new PrologException("找不到对应的库存预占信息");
                }
                WaveStorageDO waveStorageDO = storageDOS.get(0);
                detail.setBatchId(waveStorageDO.getBatchId());
                detail.setQuantity(vo.getRedQty());
                // 红冲移盘点库为无实物库存
                detail.setSubStatus("1");
                detail.setLocatorId(waveStorageDO.getLocatorId());
                if (locatorId != null)
                    detail.setExtParams(MapUtils.put("adjustType", "2").put("takeLocatorId", locatorId).getMap());
                validList.add(invStockOut);

                // 通过billId查询得到订单数据
                WaveBillDO bill = billMapper.findById(vo.getBillId(), WaveBillDO.class);
                WaveBillDDO billD = billDMapper.findById(vo.getBillDId(), WaveBillDDO.class);
                if (null != waveStorageDO.getLocatorId()) {
                    // 无计划损溢VO
                    WmsAdjustAddVO wmsAdjustAddVO = new WmsAdjustAddVO();
                    wmsAdjustAddVO.setDcId(waveStorageDO.getBldgId());
                    wmsAdjustAddVO.setWarehouseId(warehouseId);
                    wmsAdjustAddVO.setCargoOwnerId(bill.getConsignorId());
                    wmsAdjustAddVO.setWhLocatorId(locatorId);
                    wmsAdjustAddVO.setItemId(billD.getItemId());
                    wmsAdjustAddVO.setBatchId(billD.getBatchNum());
                    wmsAdjustAddVO.setProductionDate(waveStorageDO.getProductionDate());
                    wmsAdjustAddVO.setBatchExpiredDate(waveStorageDO.getExpiredDate());
                    wmsAdjustAddVO.setQuantity(vo.getRedQty());
                    wmsAdjustAddVO.setConversionRate(billD.getConversionRate());
                    wmsAdjustAddVO.setBatchNum(billD.getBatchNum());
                    wmsAdjustAddVO.setUom(billD.getCaseUom());
                    wmsAdjustAddVO.setStockStatus(billD.getStockStatus());
                    wmsAdjustAddVO.setAdjustType("1"); // 无计划盘点
                    wmsAdjustAddVO.setManufacturerLotNum(billD.getManufacturerLotNum());
                    wmsAdjustAddVO.setPieceQuantity(vo.getRedQty()); // 损溢数量
                    wmsAdjustAddVO.setPieceAccount(BigDecimal.ZERO);
                    wmsAdjustAddVO.setPieceAccountFact(vo.getRedQty());
                    wmsAdjustAddVO.setType(1); // 数量调整
                    wmsAdjustAddVO.setIsAdd(1); // 是否是是新增账存(0否1是)
                    wmsAdjustAddVO.setAdjustHeaderId(vo.getBillId());
                    wmsAdjustAddVO.setAutoBillNum(bill.getSrcCode());
                    adjustAddVOList.add(wmsAdjustAddVO);
                }
            }
            RestMessage restMessage = invClient.redAdjustStock(validList);
            if (!restMessage.isSuccess()) {
                throw new BizException("拣货红冲调用库存接口失败" + restMessage.getMessage());
            }
            if (CollectionUtil.isNotEmpty(adjustAddVOList)) {
                for (WmsAdjustAddVO wmsAdjustAddVO : adjustAddVOList) {
                    operateResource.saveAdjust(wmsAdjustAddVO);
                }
            }
        }
    }


    @Override
    @FuncImpl(name = "冲红调整库存", func = OutBoundFunc.updateStock2.class, description = "冲红调整库存")
    public Map<String,Object> updateStock2(List<UpdateStockVO> stockVOList, String warehouseId, String locatorId, String redType) {
        Map<String,Object> result = new HashMap<>();
        for (UpdateStockVO stockVO : stockVOList) {
            result.put(stockVO.getPickTaskDId(),"0");
        }
        Set<String> itemIdSet = new HashSet<>();
        if (stockVOList.size() > 0) {
            ValidList<InvStockOut> validList = new ValidList<>();
            List<WmsAdjustAddVO> adjustAddVOList = new ArrayList<>();
            String pickName = stockVOList.get(0).getPickName();
            for (UpdateStockVO vo : stockVOList) {
                InvStockOut invStockOut = new InvStockOut();
                List<InvStockOutDetail> details = new ArrayList<>();
                InvStockOutDetail detail = new InvStockOutDetail();
                details.add(detail);
                invStockOut.setDetails(details);
                invStockOut.setBillId(vo.getBillId());
                invStockOut.setLineBillId(vo.getBillDId());
                invStockOut.setWarehouseId(warehouseId);
                List<WaveStorageDO> storageDOS = waveStorageMapper.getStorageByPickTaskDId(vo.getPickTaskDId());
                if (storageDOS.size() != 1) {
                    throw new PrologException("找不到对应的库存预占信息");
                }
                WaveStorageDO waveStorageDO = storageDOS.get(0);
                itemIdSet.add(waveStorageDO.getItemId());
                //修改波次预占数量减去 冲红数量操作
                BigDecimal qty = waveStorageDO.getQty().subtract(vo.getRedQty());
                if (qty.compareTo(BigDecimal.ZERO) < 0) {
                    qty = BigDecimal.ZERO;
                }
                long updCount = waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("qty", qty).getMap(), WaveStorageDO.class);
                log.info("拣货冲红-修改波次预占数量减去冲红数量操作结果：" + updCount + ",picktaskdid:" + vo.getPickTaskDId());
                detail.setBatchId(waveStorageDO.getBatchId());
                detail.setQuantity(vo.getRedQty());
                detail.setLocatorId(waveStorageDO.getLocatorId());
                if (locatorId != null)
                    detail.setExtParams(MapUtils.put("adjustType", "2").put("takeLocatorId", locatorId).getMap());
                validList.add(invStockOut);


                // 通过billId查询得到订单数据
                WaveBillDO bill = billMapper.findById(vo.getBillId(), WaveBillDO.class);
                WaveBillDDO billD = billDMapper.findById(vo.getBillDId(), WaveBillDDO.class);
                if (null != waveStorageDO.getLocatorId()) {
                    // 无计划损溢VO
                    WmsAdjustAddVO wmsAdjustAddVO = new WmsAdjustAddVO();
                    wmsAdjustAddVO.setDcId(waveStorageDO.getBldgId());
                    wmsAdjustAddVO.setWarehouseId(warehouseId);
                    wmsAdjustAddVO.setCargoOwnerId(bill.getConsignorId());
                    wmsAdjustAddVO.setWhLocatorId(locatorId);
                    wmsAdjustAddVO.setItemId(billD.getItemId());
                    wmsAdjustAddVO.setBatchId(vo.getBatchId());
                    wmsAdjustAddVO.setProductionDate(waveStorageDO.getProductionDate());
                    wmsAdjustAddVO.setBatchExpiredDate(waveStorageDO.getExpiredDate());
                    wmsAdjustAddVO.setConversionRate(billD.getConversionRate());
                    wmsAdjustAddVO.setBatchNum(billD.getBatchNum());
                    wmsAdjustAddVO.setUom(billD.getCaseUom());
                    wmsAdjustAddVO.setStockStatus(billD.getStockStatus());
                    wmsAdjustAddVO.setAdjustType("1"); // 无计划盘点
                    wmsAdjustAddVO.setManufacturerLotNum(billD.getManufacturerLotNum());
                    // 损溢数量
                    wmsAdjustAddVO.setPieceQuantity(vo.getRedQty().negate());
                    //差异数
                    wmsAdjustAddVO.setQuantity(vo.getRedQty().negate());
                    //总数量
                    wmsAdjustAddVO.setPieceAccount(vo.getRedQty());
                    //实盘数
                    wmsAdjustAddVO.setPieceAccountFact(BigDecimal.ZERO);
                    wmsAdjustAddVO.setType(1); // 数量调整
                    wmsAdjustAddVO.setAdjustHeaderId(vo.getBillId());
                    wmsAdjustAddVO.setAutoBillNum(bill.getSrcCode());
                    wmsAdjustAddVO.setEnterpriseId(bill.getEnterpriseId());
                    adjustAddVOList.add(wmsAdjustAddVO);
                }
            }
            log.info("冲红数量调整参数:" + JSON.toJSONString(validList));
            //库存转移到盘点库
            RestMessage restMessage = invClient.redAdjustStock(validList);
            if (!restMessage.isSuccess()) {
                throw new BizException("拣货红冲调用库存接口失败" + restMessage.getMessage());
            }
            //生成损益单
            if (CollectionUtil.isNotEmpty(adjustAddVOList)) {
//                getUserDtoKeyAndSetCache(pickName);
                for (WmsAdjustAddVO wmsAdjustAddVO : adjustAddVOList) {
                    log.info("save adjust:{}", JSON.toJSONString(wmsAdjustAddVO));
                    RestMessage<?> adjust = operateResource.saveAdjust(wmsAdjustAddVO);
                    cn.hutool.core.lang.Assert.isTrue(adjust.isSuccess(), adjust.getMessage());
                }
            }
        }

        /**
         * 如下为EIS短拣重新定位库存逻辑
         * 根据品和托盘查询出所有可用库存,托盘号是用来排除掉这个托盘的.因为这个托盘号已出库造成了短拣;
         * 查询出库存后重新插入预占,插入预占时需要校验库存是否足够;足够则生成预占,不足则继续查找逻辑;
         */
        if (CollUtil.isNotEmpty(stockVOList)) {
            List<BaseMtlItemMst> items = RestMsgHelper.getData(itemClient.getListByIds(itemIdSet));
            // 盘点集合VO
            List<UpdateStockVO> pdList = new ArrayList<>();
            List<OutBoundRequestItemVO> eisParams = Lists.newArrayList();
            ValidList<InvStockOut> invStock = new ValidList<>();
            for (UpdateStockVO vo : stockVOList) {
                WmsInvStockQtyQueryVO queryVO = new WmsInvStockQtyQueryVO();
                PickTaskD pickTaskD = pickTaskDMapper.findById(vo.getPickTaskDId(), PickTaskD.class);
                PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
                WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                WaveBillDO waveBillDO = billMapper.findById(waveStorageDO.getBillId(), WaveBillDO.class);
                queryVO.setEnterpriseId(pickTaskH.getEnterpriseId());
                queryVO.setWarehouseId(pickTaskH.getWarehouseId());
                queryVO.setItemId(pickTaskD.getItemId());
//                queryVO.setContainerCode(pickTaskD.getContainerCode());
                queryVO.setStatus("1"); // 默认合格库存
                queryVO.setSubStatus("1");
                log.info("updateStock2 queryDeviceStockList:{}", JSONObject.toJSONString(queryVO));
                RestMessage<List<WmsInvStockQtyVO>> restMessage = invClient.queryDeviceStockList(queryVO);
                log.info("updateStock2 deviceStockList:{}",JSON.toJSONString(restMessage));
                if (!restMessage.isSuccess()) {
                    log.info("商品无库存,将短缺数量增加至订单的冲红数量，入盘点库，并重新调用申请发票接口");
                    pdList.add(vo);
                } else {
                    List<WmsInvStockQtyVO> stockQtyVOList = restMessage.getData();
                    if (CollUtil.isEmpty(stockQtyVOList)) {
                        continue;
                    }
                    stockQtyVOList = stockQtyVOList.stream().filter(item -> "AGVL".equals(item.getWarehouseAreaCategory())).collect(Collectors.toList());
                    if (CollUtil.isEmpty(stockQtyVOList)) {
                        continue;
                    }
                    List<WmsInvStockQtyVO> voList = stockQtyVOList.stream().filter(s -> s.getItemId().equals(pickTaskD.getItemId()) && s.getManufacturerLotNum().equals(waveStorageDO.getManufactureLotNum())).collect(toList());
                    WmsInvStockQtyVO wmsInvStockQtyVO = null;
                    if (CollUtil.isNotEmpty(voList)) {
                        wmsInvStockQtyVO = voList.stream().filter(w -> w.getAvailableQuantity().compareTo(vo.getRedQty().add(pickTaskD.getPickQty())) > 0).findFirst().orElse(null);
                    } else {
                        wmsInvStockQtyVO = stockQtyVOList.stream().filter(w -> w.getAvailableQuantity().compareTo(vo.getRedQty()) > 0).findFirst().orElse(null);
                    }
                    log.info("updateStock2,重新匹配库存数据：{}",JSON.toJSONString(wmsInvStockQtyVO));
                    if (null != wmsInvStockQtyVO) {
                        // 说明按商品+批号判断(设备库)找到了可用库存
                        // 拆分原托盘任务并推送EIS
                        // 拣货明细行拆单处理,拆单的同时出库预占同时拆分
                        WaveStorageDO newWaveStorageDO = new WaveStorageDO();
                        BeanUtils.copyProperties(waveStorageDO, newWaveStorageDO);
                        String waveStorageId = String.valueOf(SnowFlakeUtils.getId());
                        newWaveStorageDO.setId(waveStorageId);
                        newWaveStorageDO.setQty(vo.getRedQty());
                        newWaveStorageDO.setContainerCode("N/A");
                        newWaveStorageDO.setBatchId(wmsInvStockQtyVO.getBatchId());
                        newWaveStorageDO.setBatchNum(wmsInvStockQtyVO.getBatchNum());
                        newWaveStorageDO.setLocatorId(wmsInvStockQtyVO.getLocatorId());
                        newWaveStorageDO.setLocatorType(wmsInvStockQtyVO.getLocatorType());
                        newWaveStorageDO.setLocatorCode(wmsInvStockQtyVO.getLocatorCode());
                        newWaveStorageDO.setWarehouseAreaCode(wmsInvStockQtyVO.getWarehouseAreaCode());
                        newWaveStorageDO.setAreaCategory(wmsInvStockQtyVO.getWarehouseAreaCategory());
                        waveStorageDO.setQty(waveStorageDO.getQty().subtract(newWaveStorageDO.getQty()));
                        //拣货头
                        PickTaskH newPickTaskH = new PickTaskH();
                        BeanUtils.copyProperties(pickTaskH, newPickTaskH);
                        newPickTaskH.setPickTaskId(String.valueOf(SnowFlakeUtils.getId()));
                        newPickTaskH.setStatus("0");
                        newPickTaskH.setContainerNo(null);
                        newPickTaskH.setQty(vo.getRedQty());
                        newPickTaskH.setPickQty(BigDecimal.ZERO);
                        newPickTaskH.setCheckQty(BigDecimal.ZERO);
                        newPickTaskH.setUnPickQty(BigDecimal.ZERO);
                        //拣货明细
                        PickTaskD newPickTaskD = new PickTaskD();
                        BeanUtils.copyProperties(pickTaskD, newPickTaskD);
                        newPickTaskD.setContainerCode(null);
                        newPickTaskD.setPickTaskId(newPickTaskH.getPickTaskId());
                        newPickTaskD.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
                        newPickTaskD.setQty(vo.getRedQty());
                        newPickTaskD.setSrcPickTaskDId(pickTaskD.getPickTaskDId());
                        newPickTaskD.setWaveStorageId(waveStorageId);
                        newPickTaskD.setFlowStatus("0");
                        newPickTaskD.setPickQty(BigDecimal.ZERO);
                        newPickTaskD.setPickTime(null);
                        newPickTaskD.setBatchId(wmsInvStockQtyVO.getBatchId());
                        newPickTaskD.setLocatorId(wmsInvStockQtyVO.getLocatorId());
                        newPickTaskD.setSaleRedQty(null);
                        pickTaskD.setQty(pickTaskD.getQty().subtract(newPickTaskD.getQty()));

                        // 插入和更新
                        waveStorageMapper.save(newWaveStorageDO);
                        waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("qty", waveStorageDO.getQty()).getMap(), WaveStorageDO.class);
                        pickTaskDMapper.save(newPickTaskD);
                        pickTaskHMapper.save(newPickTaskH);
                        pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("qty", pickTaskD.getQty()).getMap(), PickTaskD.class);

                        // 推送EIS
                        BaseMtlItemMst itemMst = items.stream().filter(i -> i.getItemId().equals(newWaveStorageDO.getItemId())).findFirst().orElse(null);
                        List<BaseMtlItemUomConversions> uomList = itemMst.getBaseMtlItemUomConversionsList();
                        BaseMtlItemUomConversions conversions = uomList.stream().max(Comparator.comparing(BaseMtlItemUomConversions::getConversionRate)).get();

                        OutBoundRequestItemVO eisParam = new OutBoundRequestItemVO();
                        OutBoundRequestEnum outBoundRequestEnum = OutBoundRequestEnum.get(waveBillDO.getType());
                        eisParam.setWorkType(outBoundRequestEnum.getWorkType());
                        eisParam.setBusinessType(outBoundRequestEnum.getBusinessType());
                        eisParam.setWaveNo(waveBillDO.getWaveId());
                        eisParam.setTaskId(newPickTaskD.getPickTaskId());
                        eisParam.setBillNo(newPickTaskD.getSrcId());
                        eisParam.setStr1("1");
                        eisParam.setStr2("1");
                        eisParam.setCompanyId(waveBillDO.getShipperId());
                        eisParam.setCompanyName(waveBillDO.getShipperName());
                        eisParam.setContainerNo("N/A".equals(newWaveStorageDO.getContainerCode()) ? "" : newWaveStorageDO.getContainerCode());
                        eisParam.setTaskLineId(newPickTaskD.getPickTaskDId());
                        eisParam.setPriority(10.0D);
                        eisParam.setEnterpriseId(newWaveStorageDO.getEnterpriseId());
                        eisParam.setItemId(newPickTaskD.getItemId());
                        eisParam.setLotId(newPickTaskD.getBatchId());
                        eisParam.setQty(newPickTaskD.getQty().toString());
                        eisParam.setLocNo(newWaveStorageDO.getLocatorCode());
                        eisParam.setOwnerId(waveBillDO.getConsignorId());
                        eisParam.setPackId(conversions.getItemUomId());
                        //四向库：MJZ;AGV整件药品托盘库：AGVZ;AGV整件食品托盘库：AGVSP;AGV整件器械托盘库：AGVQX;拆零库:AGVL(包含食品、器械、药品);
                        eisParam.setWmsLocationCode("MJK".equals(newWaveStorageDO.getAreaCategory()) ? "MJZ" : newWaveStorageDO.getAreaCategory());
                        eisParam.setOriginalArea("");
                        eisParam.setTargetArea("");
                        eisParam.setTargetLocation("");
                        eisParam.setInventoryShortageType(2);
                        eisParam.setIsOver("0");
                        eisParam.setIsCheck("0");
                        eisParam.setIsMaterial("WLK".equals(newWaveStorageDO.getAreaCategory()) ? "2" : "1");
                        eisParam.setOldTaskLineId(pickTaskD.getPickTaskDId());
                        eisParams.add(eisParam);
                        log.info("设备库短拣结束生成拣货数据,下发数据到EIS");

                        //生成新预占
                        InvStockOut invStockOut = new InvStockOut();
                        invStockOut.setBillId(newPickTaskD.getBillId());
                        invStockOut.setLineBillId(newPickTaskD.getBillDId());
                        invStockOut.setSrcId(newPickTaskD.getSrcId());
                        invStockOut.setSrcLineId(newPickTaskD.getSrcLineId());
                        invStockOut.setWarehouseId(newPickTaskD.getWarehouseId());

                        InvStockOutDetail detail = new InvStockOutDetail();
                        detail.setBatchId(newPickTaskD.getBatchId());
                        detail.setLocatorId(newPickTaskD.getLocatorId());
                        detail.setQuantity(newPickTaskD.getQty());
                        invStockOut.setDetails(CollUtil.toList(detail));

                        invStock.add(invStockOut);

                    } else {
                        log.info("商品无库存,将短缺数量增加至订单的冲红数量，入盘点库，并重新调用申请发票接口");
                        pdList.add(vo);
                    }
                }
            }
            // 确实无库存走盘点逻辑
//            if (CollUtil.isNotEmpty(stockVOList)) {
//                pickTaskService.updateStock(stockVOList, warehouseId, locatorId);
//            }
            if (CollectionUtil.isNotEmpty(eisParams)) {
                new Thread(() -> {
                    try {
                        Thread.sleep(8000);
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                    OutBoundRequestVO eisParam = new OutBoundRequestVO();
                    eisParam.setMsgId(IdUtil.fastSimpleUUID());
                    eisParam.setWarehouseId(warehouseId);
                    eisParam.setGroupOrderPolicy("0");
                    eisParam.setSubList(eisParams);
                    log.info("eisHandler.outBoundRequest：{}", JSONObject.toJSONString(Collections.singletonList(eisParam)));
                    eisHandler.outBoundRequest(Collections.singletonList(eisParam));
                }).start();

                //生成库存预占
                if(invStock.size() > 0){
                    log.info("短拣重新定位库存，生成出库预占入参：{}",JSON.toJSONString(invStock));
                    try {
                        RestMessage restMessage = invClient.outStock(invStock);
                        log.info("短拣重新定位库存，生成出库预占返回结果：{}",JSON.toJSONString(restMessage));
                    }catch (Exception e){
                        e.printStackTrace();
                        log.info("短拣重新定位库存，生成出库预占失败："+e.getMessage());
                    }

                }

                for (OutBoundRequestItemVO eisParam : eisParams) {
                    result.put(eisParam.getOldTaskLineId(),"1");
                }
            }
        }
        return result;
    }

    private UserDTO setCache4Eis(String workNumber, String enterpriseId) {
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(workNumber);
        userDTO.setId(workNumber);
        userDTO.setNickname(workNumber);
        userDTO.setEnterpriseId(enterpriseId);
        if (!HystrixRequestContext.isCurrentThreadInitialized()) {
            HystrixRequestContext.initializeContext();
            HystrixVarUtil.setUserKey(workNumber);
        }
        setUser2Redis(workNumber, userDTO);
        return userDTO;
    }

    /**
     * 保存外复核数据
     *
     * @param finalList
     * @param pickTaskDIds
     * @param pickOrderId
     * @param bldgId
     * @return
     */
    @Transactional
    @FuncImpl(name = "更新拣货任务主表", func = OutBoundFunc.saveBarcode.class, description = "更新拣货任务主表")
    public boolean saveBarcode(
            List<PickTaskH> finalList,
            List<String> pickTaskDIds,
            String pickOrderId,
            String bldgId,
            String warehouseId,
            String enterpriseId
    ) {
        String redisKey = "wms:pick:serial:" + DateUtil.format(DateUtil.date(), DatePattern.NORM_DATE_FORMAT);
        RedisAtomicInteger counter = new RedisAtomicInteger(redisKey, redisTemplate.getConnectionFactory());
        counter.expireAt(DateUtil.endOfDay(DateUtil.date()));
        int norCnt = 0;
        int mjkCnt = 0;
        int agvzCnt = 0;
        RestMessage<Map<String, BusinessControl>> restMessage = strategyResource.getControlByCodes(new String[]{"BARCODE_SPLIT_NUM", "BARCODE_SPLIT_NUM_MJK", "BARCODE_SPLIT_NUM_AGVZ"}, warehouseId, null, enterpriseId, null);
        if (restMessage.isSuccess() && restMessage.getData() != null) {
            Map<String, BusinessControl> map = restMessage.getData();
            if (map.containsKey("BARCODE_SPLIT_NUM")) {
                norCnt = Integer.parseInt(map.get("BARCODE_SPLIT_NUM").getRegValue());
            }
            if (map.containsKey("BARCODE_SPLIT_NUM_MJK")) {
                mjkCnt = Integer.parseInt(map.get("BARCODE_SPLIT_NUM_MJK").getRegValue());
            }
            if (map.containsKey("BARCODE_SPLIT_NUM_AGVZ")) {
                agvzCnt = Integer.parseInt(map.get("BARCODE_SPLIT_NUM_AGVZ").getRegValue());
            }
        }
        RestMessage<List<BaseCommonDict>> replenishSlidMsg = commonClient.getDictBasicListByCodes("replenish_qy", null);
        RestMessage<List<BaseCommonDict>> outSlidMsg = commonClient.getDictBasicListByCodes("OUT_LINE_QY", null);

        for (PickTaskH pickTaskH : finalList) {
            String slidWayNo = "";
            if (pickTaskH.getType() == null) {
                throw new BizException("拣货任务类型不正确！");
            } else if (pickTaskH.getType() == 0) {
                if (!outSlidMsg.isSuccess() || CollUtil.isEmpty(outSlidMsg.getData())) {
                    throw new BizException("未配置运输路线与滑道对应关系！");
                }
                // 查询运输路线
                String shipLineId = pickTaskHMapper.findShipLineId(pickTaskH.getPickTaskId());
                if (null == shipLineId) {
                    throw new BizException("当前订单没有运输路线！");
                }
                BaseCommonDict dict = outSlidMsg.getData().stream().filter(var -> var.getDictCode().equals(shipLineId)).findFirst().orElse(null);
                if (null == dict) {
                    throw new BizException("当前运输路线未配置与滑道对应关系！");
                }
                slidWayNo = dict.getAttr1();
            } else if (pickTaskH.getType() == 1) {
                if (!replenishSlidMsg.isSuccess() || CollUtil.isEmpty(replenishSlidMsg.getData())) {
                    throw new BizException("未配置库区与滑道对应关系！");
                }
            } else {
                throw new BizException("拣货任务类型不正确！");
            }
            int pickType = pickTaskH.getType();
            pickTaskH.setPickOrderId(pickOrderId);
            pickTaskH.setStatus("1");
            pickTaskHMapper.updateFields(pickTaskH, FieldSelector.newInstance().include("status", "pickOrderId"));

            String bldgName = pickTaskH.getBldgName();
            // 拣货任务并且是整件索取，生成标签打印数据
            if (pickTaskH.getPickTaskType() == 0) {
                List<PickTaskD> pickTaskDList = pickTaskDMapper.findByMap(MapUtils.put("pickTaskId", pickTaskH.getPickTaskId()).getMap(), PickTaskD.class);
                if (pickTaskDList.size() > 0) {
                    for (PickTaskD pickTaskD : pickTaskDList) {
                        if (pickTaskD.getVersion() != null && pickTaskD.getVersion() > 0) {
                            //根据乐观锁判断是否已经生成标签
                            continue;
                        }
                        WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                        if (pickType == 1) {
                            // 查询目标货位所属库区
                            MoveTaskDO moveTaskDO = moveTaskMapper.getMoveTask(pickTaskD.getPickTaskDId(), warehouseId);
                            RestMessage<List<BaseWmsWarehouseArea>> all = warehouseResource.getWarehouseAreaBasicInfos(new String[]{moveTaskDO.getDestWarehouseAreaId()});
                            if (!all.isSuccess() || CollUtil.isEmpty(all.getData())) {
                                throw new BizException("补货上架库存查询失败！");
                            }
                            BaseWmsWarehouseArea area = all.getData().get(0);
                            BaseCommonDict dict = replenishSlidMsg.getData().stream().filter(var -> var.getDictCode().equals(area.getWarehouseAreaCode())).findFirst().orElse(null);
                            if (null == dict) {
                                throw new BizException("当前库区未配置与滑道对应关系！");
                            }
                            slidWayNo = dict.getAttr1();
                        }
                        BarcodeHDO barCodeHDO = new BarcodeHDO();
                        barCodeHDO.setBarcode(pickTaskD.getPickTaskDId());
                        barCodeHDO.setId(String.valueOf(SnowFlakeUtils.getId()));
                        barCodeHDO.setBillGroupId(pickTaskH.getBillGroupId());
                        barCodeHDO.setType("1"); // 整件拣选码
                        barCodeHDO.setStatus('0');
                        barCodeHDO.setWarehouseId(pickTaskH.getWarehouseId());
                        barCodeHDO.setBldgId(bldgId);
                        barCodeHDO.setBldgName(bldgName);
                        barCodeHDO.setCheckStatus("0");
                        ModelUtils.generateBaseData(barCodeHDO, userTemplate::getUserDTO);
                        barcodeHMapper.save(barCodeHDO);
                        List<BarCodeDDO> barCodeDDOList = new ArrayList<>();
                        // 查询商品的包装件数
                        Map<String, String> itemMap = pickTaskHMapper.getItemCode(pickTaskD.getPickTaskDId(), pickTaskH.getWarehouseId());
                        if (itemMap == null || !itemMap.containsKey("ITEM_ID")) {
                            throw new BizException("查询商品信息失败！");
                        }
                        RestMessage<List<BaseMtlItemMst>> itemMsg = itemClient.getListByIds(Collections.singleton(itemMap.get("ITEM_ID")));
                        if (null == itemMsg || !itemMsg.isSuccess() || CollUtil.isEmpty(itemMsg.getData())) {
                            throw new BizException("查询商品信息失败！");
                        }
                        BaseMtlItemMst itemMstVO2 = itemMsg.getData().stream().filter(var -> var.getItemId().equals(itemMap.get("ITEM_ID"))).findFirst().orElse(null);
                        if (null == itemMstVO2) {
                            throw new BizException("查询商品信息失败！");
                        }
                        BigDecimal js = pickTaskD.getQty().divide(itemMstVO2.getCaseConversionRate(), 0, RoundingMode.HALF_UP);
                        int loopCnt;
                        String areaCategory = waveStorageDO.getAreaCategory();
                        if (StrUtil.isNotBlank(areaCategory)) {
                            if (areaCategory.equals("MJK")) {
                                loopCnt = js.intValue() <= mjkCnt ? js.intValue() : 1;
                            } else if (areaCategory.equals("AGVZ")) {
                                loopCnt = js.intValue() <= agvzCnt ? js.intValue() : 1;
                            } else {
                                loopCnt = js.intValue() <= norCnt ? js.intValue() : 1;
                            }
                        } else {
                            loopCnt = js.intValue() <= norCnt ? js.intValue() : 1;
                            // 如果出库方式是MJK/AGVZ在线拣选，则每件一个标签， 如果是整托，则只有1个标签
                            List<InfTaskOutBackVO> outBacks = outBackMapper.findByMap(MapUtils.put("seqNo", StrUtil.isEmpty(pickTaskD.getSrcPickTaskDId()) ? pickTaskD.getPickTaskDId() : pickTaskD.getSrcPickTaskDId()).getMap(), InfTaskOutBackVO.class);
                            if (CollUtil.isNotEmpty(outBacks)) {
                                InfTaskOutBackVO infTaskOutBackVO = outBacks.get(0);
                                if (StrUtil.isNotEmpty(infTaskOutBackVO.getOuttype()) && infTaskOutBackVO.getOuttype().equals("1")) {
                                    // 整托出库，一个标签
                                    loopCnt = 1;
                                }
                                if (StrUtil.isNotEmpty(infTaskOutBackVO.getOuttype()) && infTaskOutBackVO.getOuttype().equals("2")) {
                                    // 整件出库，一件一个标签
                                    loopCnt = js.intValue();
                                }
                            }
                        }
                        for (int i = 0; i < loopCnt; i++) {
                            BarCodeDDO barCodeDDO = new BarCodeDDO();
                            Integer serialNo = counter.incrementAndGet();
                            barCodeDDO.setId(BillUtils.getBarcode(pickTaskH.getType() == 1 ? "2" : "1", "0", serialNo, slidWayNo, ""));
                            barCodeDDO.setBarcodeId(barCodeHDO.getId());
                            barCodeDDO.setWmsPickTaskDId(pickTaskD.getPickTaskDId());
                            barCodeDDO.setEnterpriseId(pickTaskH.getEnterpriseId());
                            barCodeDDO.setWarehouseId(pickTaskH.getWarehouseId());
                            if (loopCnt > 1) {
                                barCodeDDO.setQty(itemMstVO2.getCaseConversionRate());
                            } else {
                                barCodeDDO.setQty(pickTaskD.getQty());
                            }
                            barCodeDDO.setContainerCode(loopCnt == 1 ? js.intValue() + "" : (i + 1) + "/" + loopCnt);
                            barCodeDDO.setIsPiece(0);
                            barCodeDDO.setCheckStatus("0");
                            barCodeDDO.setItemCode(itemMstVO2.getItemCode());
                            barCodeDDO.setItemId(itemMstVO2.getItemId());
                            ModelUtils.generateBaseData(barCodeDDO, userTemplate::getUserDTO);
                            barCodeDDOList.add(barCodeDDO);
                        }
                        barcodeDMapper.saveBatch(barCodeDDOList);
                        int row = pickTaskDMapper.updateVersion(pickTaskD.getVersion() == null ? 0 : pickTaskD.getVersion(), pickTaskD.getPickTaskDId());
                        if (row != 1) {
                            throw new BizException("生成标签异常！重复生成");
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * 扣减库存,并回传ERP
     * 拣货确认时，如果明显的红冲方式为还原库位，需要传入还原数量进行还原
     *
     * @param warehouseId
     */
    @Transactional
    public void invStockConfirm(PickTaskD pickTaskD, String warehouseId, BigDecimal returnQty) {
        // 业务参数配置内/外复核回传ERP，使用 PostBackErpHandle by Huanglh 20220112
        //@TODO 扣减库存
        log.info("开始扣减库存");
        InvStockPartCheckOut invStockCheck = new InvStockPartCheckOut();
        if (pickTaskD == null) {
            return;
        }
        // 查询预占信息
        WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
        if (null == waveStorageDO) {
            throw new BizException("未查询到预占信息！");
        }
        // 查询需要的参数 batchNum/locatorId/itemId/qty/containerCode
        invStockCheck.setContainerCode(waveStorageDO.getContainerCode());
        if (!StringUtils.isBlank(waveStorageDO.getAreaCategory()) && waveStorageDO.getAreaCategory().contains("AGVZ")) {
            invStockCheck.setContainerCodeSelectPreFlag(true);
        }
        invStockCheck.setQty(pickTaskD.getQty());
        invStockCheck.setLocatorId(waveStorageDO.getLocatorId());
        invStockCheck.setItemId(waveStorageDO.getItemId());
        invStockCheck.setLineBillIds(new String[]{waveStorageDO.getBillDId()});
        invStockCheck.setBatchNum(waveStorageDO.getBatchNum());
        invStockCheck.setReturnToStockQty(returnQty);
        log.info("请求参数：{}", JSONObject.toJSONString(invStockCheck));
        RestMessage restMessage = invClient.outPartStockCheck(invStockCheck);
        log.info("返回参数：{}", JSONObject.toJSONString(restMessage));
        if (!restMessage.isSuccess()) {
            throw new BizException("扣减库存失败: " + restMessage.getMessage() +
                    String.format("，入参为：[仓库：%s][任务明细ID：%s]", warehouseId, JSONObject.toJSONString(pickTaskD.getPickTaskDId())));
        }
        log.info("扣减库存成功");
    }

    /**
     * 回传ERP
     *
     * @param omsBillIds
     */
    @Transactional
    @Override
    @FuncImpl(name = "回传ERP", func = OutBoundFunc.saveOutcomingRecord.class, description = "回传ERP")
    public void saveOutcomingRecord(List<String> omsBillIds) {
        if (omsBillIds.size() > 0) {
            // 1.昆药版本,rabbitmq方式回传
            /*for (String omsBillId : omsBillIds) {
                EtlMessage etlMessage = new EtlMessage();
                etlMessage.setId(omsBillId);
                etlMessage.setEtlType(EtlTypeConstants.out_do_w2o);
                try {
                    exchangeSender.send(etlMessage);
                } catch (Exception e) {
                    throw new BizException("外复核确认，回传ERP，rabbitmq发送消息失败！");
                }
            }*/

            // 2.正方体版本,保存到出库中间表
            String[] ids = omsBillIds.toArray(new String[omsBillIds.size()]);
            Criteria crtH = Criteria.forClass(OutcomingRecordH.class);
            Criteria crtD = Criteria.forClass(OutcomingRecordD.class);
            crtH.setRestriction(Restrictions.in("billid", ids));
            crtD.setRestriction(Restrictions.in("billid", ids));
            outcomingRecordHMapper.deleteByCriteria(crtH);
            outcomingRecordDMapper.deleteByCriteria(crtD);
            for (String omsBillId : omsBillIds) {
                List<OutcomingRecordH> listH = outcomingRecordHMapper.getH(omsBillId);
                if (listH.size() > 0) {
                    outcomingRecordHMapper.saveBatch(listH);
                }
                List<OutcomingRecordD> listD = outcomingRecordHMapper.getD(omsBillId);
                if (CollUtil.isNotEmpty(listD)) {
                    List<String> lineIds = listD.stream().map(OutcomingRecordD::getLineId).distinct().collect(Collectors.toList());
                    List<OutcomingRecordD> saveRecordDList = new ArrayList<>();
                    if (lineIds.size() > 0) {
                        for (String lineId : lineIds) {
                            // 先找批号不为空的
                            OutcomingRecordD outcomingRecordD = listD.stream().filter(d -> d.getLineId().equals(lineId) && !StringUtils.isBlank(d.getLotNo())).findFirst().orElse(null);
                            if (null == outcomingRecordD) {
                                OutcomingRecordD recordD = listD.stream().filter(d -> d.getLineId().equals(lineId)).findFirst().orElse(null);
                                saveRecordDList.add(recordD);
                            } else {
                                saveRecordDList.add(outcomingRecordD);
                            }
                        }
                    }
                    if (CollUtil.isNotEmpty(saveRecordDList)) {
                        outcomingRecordDMapper.saveBatch(saveRecordDList);
                    }
                }
            }
            // 调用接口平台回传OMS
            try {
                if (StringUtils.isEmpty(outComingRecordBack)) {
                    throw new BizException("请求路径配置为空");
                }
                String url = outComingRecordBack;
                log.info("调用OMS接口URL:{}", JSONUtil.toJsonStr(url));
                List<OutcomingRecordHDto> backList = pickTaskServiceImpl.queryOutboundDataToOms(omsBillIds);
                log.info("调用OMS接口入参:{}", JSONUtil.toJsonStr(backList));
                String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
                JSONObject parse = JSONObject.parseObject(result);
                log.info("调用OMS接口返回参数:{}", parse);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    // 业务参数配置内/外复核回传ERP，使用 PostBackErpHandle by Huanglh 20220112
    // 红冲用
    private void saveOutcomingRecordForRed(List<String> omsBillIds, String warehouseId) {
        // 红冲只需要需要判断一个业务配置参数
        if (omsBillIds.size() > 0) {
            IStrategyHandle strategyHandle = strategySelector.selectHandle(Arrays.asList(
                    STRATEGY_CODE.POST_BACK_ERP__MQ__ON), warehouseId, "do");
            strategyHandle.execute(omsBillIds);
        }
    }

    @Override
    public Employee getEmployee(String operatorCode, String enterpriseId) {
        RestMessage<Employee> restMessage = powerResource.getByNum(operatorCode, null, enterpriseId);
        if (!restMessage.isSuccess() || restMessage.getData() == null)
            throw new RuntimeException("查询员工信息失败！" + restMessage.getMessage());
        Employee employee = restMessage.getData();
        return employee;
    }

    /**
     * 调用接口平台
     *
     * @param interfaceId
     * @param param
     * @return
     */
    public JSONObject askIntegration(String interfaceId, Map<String, Object> param) {
        if (!StringUtils.isBlank(integrationToken) && integrationToken.equalsIgnoreCase("prod"))
            integrationToken = "$2a$12$PHVUZPLUswQVz0Mj.FdzmeF5lC.eqQEGOtA8CN8OzpH7XC8Mf3ste";
        Map<String, Object> paramMap = MapUtils.put("token", integrationToken).put("interfaceId", interfaceId).getMap();
        if (param != null)
            paramMap.put("data", param);
        String result = integrationResource.httpService(paramMap);
        JSONObject json = JSONObject.parseObject(result);
        if (json.containsKey("success") && !json.getBoolean("success")) {
            throw new PrologException("接口平台调用错误:" + json);
        }
        return json;
    }

    //更新明细状态
    public void updatePickTaskD(String[] hIds, String enterpriseId, String flowStatus) {
        Criteria crt = Criteria.forClass(PickTaskD.class);
        Restriction r1 = Restrictions.in("pickTaskId", hIds);
        Restriction r2 = Restrictions.eq("enterpriseId", enterpriseId);
        crt.setRestriction(Restrictions.and(r1, r2));
        pickTaskDMapper.updateMapByCriteria(MapUtils.put("flowStatus", flowStatus).getMap(), crt);
    }

    //根据条码单件拣货确认
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void confirmPickTaskByBarcode(String barcode) {
        // 根据barcode查询任务信息，组装确认参数进行拣货确认
        BarCodeDDO barCodeDDO = barcodeDMapper.findById(barcode, BarCodeDDO.class);
        if (null == barCodeDDO) {
            throw new BizException("标签不存在！");
        }
        String pickTaskDId = barCodeDDO.getWmsPickTaskDId();
        PickTaskD pickTaskD = pickTaskDMapper.findById(pickTaskDId, PickTaskD.class);
        if (null == pickTaskD) {
            throw new BizException("拣货任务明细不存在！");
        }
        PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
        if (null == pickTaskH) {
            throw new BizException("拣货任务不存在！");
        }
        if (pickTaskH.getPickTaskType() != 0) {
            throw new BizException("只能确认整件任务!");
        }
        if (Integer.parseInt(pickTaskD.getFlowStatus()) < 3) {
            BigDecimal pickQty = pickTaskD.getQty();
            UserDTO userDTO = userTemplate.getUserDTO();
            String operatorId = "EIS";
            String operatorCode = "EIS";
            String operatorName = "EIS";
            if (null != userDTO) {
                operatorId = userDTO.getId();
                operatorCode = userDTO.getUsername();
                operatorName = userDTO.getNickname();
            }
            pickTaskDMapper.updateMapById(
                    pickTaskDId,
                    MapUtils.put("pickQty", pickQty)
                            .put("pickerId", operatorId)
                            .put("pickerNo", operatorCode)
                            .put("pickerName", operatorName)
                            .put("pickTime", DateUtil.format(DateUtil.date(), DatePattern.NORM_DATE_FORMAT))
                            .put("flowStatus", "3")
                            .getMap(),
                    PickTaskD.class
            );
        }
        // 如果是补货任务，更新补货表状态
        List<String> lineIds = new ArrayList<>();
        List<ReplenishDetailVO> replenishDetailVOList = new ArrayList<>();
        if (pickTaskH.getType() == 1) {
            String moveId = pickTaskHMapper.getMoveTaskId(pickTaskDId, pickTaskH.getWarehouseId());
            if (moveId != null) {
                MoveTaskDO move = moveTaskMapper.findById(moveId, MoveTaskDO.class);
                lineIds.add(move.getDetailId());
                ReplenishDetailVO replenishDetailVO = new ReplenishDetailVO();
                replenishDetailVO.setLineId(move.getDetailId());
                replenishDetailVO.setSrcLineId(pickTaskDId);
                replenishDetailVOList.add(replenishDetailVO);
            }
        }
        // 如果是整件任务，则将对应条码表更新为0-待复核索取
        if (pickTaskH.getPickTaskType() == 0) {
            List<BarCodeDDO> dList = barcodeDMapper.findByMap(MapUtils.put("wmsPickTaskDId", pickTaskDId).put("warehouseId", pickTaskH.getWarehouseId()).getMap(), BarCodeDDO.class);
            if (dList.size() > 0)
                barcodeHMapper.updateMapById(dList.get(0).getBarcodeId(), MapUtils.put("checkStatus", "0").getMap(), BarcodeHDO.class);
        }
        // 查询 拣选任务主表下明细未确认条数
        Integer count = pickTaskHMapper.getUnConfirmCount(new String[]{pickTaskDId}, pickTaskDId, pickTaskH.getEnterpriseId());
        // 如果明细都已确认，则任务主表状态更新为2：待复核
        if (count == 0) {
            //任务主表状态更新
            if (pickTaskH.getType() == 1) {
                pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("status", "5").getMap(), PickTaskH.class);
            } else {
                pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("status", "2").getMap(), PickTaskH.class);
            }
            String pickOrderId = pickTaskH.getPickOrderId();
            // 查询未确认的拣选任务
            Integer count2 = pickTaskHMapper.getUnConfirmCountH(pickTaskH.getPickTaskId(), pickOrderId, pickTaskH.getBldgId(), pickTaskD.getWarehouseId());
            // 拣选单状态更新为2：拣选完成
            if (count2 == 0) {
                pickOrderMapper.updateMapById(pickOrderId, MapUtils.put("status", "2").getMap(), PickOrder.class);
                // 回传拣选完成状态
                if (pickTaskH.getType() == 0) {
                    orderOutboundStatusBackService.sendOutboundOrderStatusOms(pickTaskH.getBillGroupId(), "", "", "", "", "30", BigDecimal.ZERO);
                }
            }
        }
        // 扣减库存
        if (pickTaskH.getType() == 0) {
            invStockConfirm(pickTaskD, pickTaskD.getWarehouseId(), BigDecimal.ZERO);
        } else {
            // 下架确认,扣减库存
            confirmReplenish.confirmReplenish(lineIds, replenishDetailVOList);
        }
    }

    /**
     * EIS回告拣货确认
     *
     * @param infTaskOutBackVO
     * @return
     */
    @Override
    public List<InfTaskOutBackVO> eisConfirm(InfTaskOutBackVO infTaskOutBackVO) {
        this.confirmPickTaskByBarcode(infTaskOutBackVO.getLabel());
        return Collections.singletonList(infTaskOutBackVO);
    }

    /**
     * 提供出库任务回告接口给EIS
     *
     * @param infTaskOutBackDTOList infTaskOutBackDTOList
     * @return RestMessage<?> rest
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @TxTransaction
    @InterfaceMethod(key = "infTaskOutBack", name = "AGV托盘四向库回告", type = InterfaceType.Receive)
    public RestMessage<List<InfTaskOutBackDTO>> infTaskOutBack(List<InfTaskOutBackDTO> infTaskOutBackDTOList) {
        if (CollectionUtil.isNotEmpty(infTaskOutBackDTOList)) {
            List<InfTaskOutBackVO> saveList = new ArrayList<>();
            List<InfTaskOutBackVO> updateList = new ArrayList<>();
            List<InfTaskOutBackVO> moveList = new ArrayList<>(); // 移库任务
            List<InfTaskOutBackDTO> upkeepList = new ArrayList<>();//养护任务
            List<InfTaskOutBackDTO> invCheckList = new ArrayList<>();//盘点任务
            InfTaskOutBackVO infTaskOutBackVO = null;
            InfTaskOutBackDTO taskOutBackDTO = infTaskOutBackDTOList.get(0);
            String locationNo = taskOutBackDTO.getLocationNo();
            String pickOrderId = String.valueOf(SnowFlakeUtils.getId());
            Calendar calendar = Calendar.getInstance();
            String backBatch = ""; // 本次回传定义一个唯一的批次，方便后续查询
            calendar.add(Calendar.MINUTE, new Random().nextInt(15) + 15);
            if (!StringUtils.isBlank(locationNo) && taskOutBackDTO.getWorkType().equals("10")) {
                // 说明为周转框回告,生成拣选单并自动完成
                PickTaskD pickTaskD = pickTaskDMapper.findById(taskOutBackDTO.getSeqNo(), PickTaskD.class);
                if (null == pickTaskD) {
                    return new RestMessage(false, "500", "EIS出库回传WMS失败,任务不存在", infTaskOutBackDTOList);
                }
                // 根据msgId判断此条数据是否已接收并处理
                InfTaskOutBackVO taskOutBackVO = wmsTaskOutBackMapper.findById(taskOutBackDTO.getMsgId(), InfTaskOutBackVO.class);
                if (null != taskOutBackVO) {
                    log.info("数据已处理,无需要在次处理,任务号:{}", taskOutBackDTO.getSeqNo());
                } else {
                    if (!StringUtils.isBlank(pickTaskD.getFlowStatus()) && !pickTaskD.getFlowStatus().equals("3")) {
                        PickOrder pickOrder = new PickOrder();
                        pickOrder.setPickOrderId(pickOrderId);
                        pickOrder.setStatus("2");
                        pickOrder.setWarehouseId(taskOutBackDTO.getWarehouseId());
                        pickOrder.setTaskCount(infTaskOutBackDTOList.size());
                        pickOrder.setOperatorId(pickTaskD.getCreator());
                        pickOrder.setOperatorName(pickTaskD.getCreatorName());
                        pickOrder.setOperatorCode(pickTaskD.getCreatorName());
                        pickOrder.setPickTaskType(1); // 周转框零货
                        pickOrder.setPrintStatus("1");
                        pickOrder.setEnterpriseId(pickTaskD.getEnterpriseId());
                        pickOrder.setGmtCreate(calendar.getTime());
                        pickOrder.setGmtModified(calendar.getTime());
                        pickOrderMapper.save(pickOrder);
                    }
                }
            }
            for (InfTaskOutBackDTO infTaskOutBackDTO : infTaskOutBackDTOList) {
                infTaskOutBackVO = new InfTaskOutBackVO();
                // 根据msgId判断此条数据是否已接收并处理
                InfTaskOutBackVO taskOutBackVO = wmsTaskOutBackMapper.findById(infTaskOutBackDTO.getMsgId(), InfTaskOutBackVO.class);
                if (null != taskOutBackVO) {
                    log.info("数据已处理,无需要在次处理,任务号:{}", infTaskOutBackDTO.getSeqNo());
                    if (StrUtil.isEmpty(taskOutBackVO.getExtend03())) {
                        updateList.add(taskOutBackVO);
                    } else if (StrUtil.isEmpty(backBatch)) {
                        backBatch = taskOutBackVO.getExtend03();
                    }
                    continue;
                } else {
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    updateList.add(infTaskOutBackVO);
                }
                if (StrUtil.isEmpty(backBatch)) {
                    backBatch = IdUtil.fastSimpleUUID();
                }

                if (null != infTaskOutBackDTO.getWorkType() && (infTaskOutBackDTO.getWorkType().equals("10") || infTaskOutBackDTO.getWorkType().equals("50"))) {
                    // 根据seqno判断任务是否存在
                    PickTaskD pickTaskD = pickTaskDMapper.findById(infTaskOutBackDTO.getSeqNo(), PickTaskD.class);
                    if (null == pickTaskD) {
                        return new RestMessage(false, "500", "EIS出库回传WMS失败,任务不存在", infTaskOutBackDTOList);
                    }
                    WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                    // 判断是否为周转框回告
                    if (!StringUtils.isBlank(infTaskOutBackDTO.getLocationNo())) {
                        if (!StringUtils.isBlank(pickTaskD.getFlowStatus()) && pickTaskD.getFlowStatus().equals("3")) {
                            log.info("数据已处理,无需要在次处理,任务号:{}", infTaskOutBackDTO.getSeqNo());
                            continue;
                        }
                        // 判断拣货数量是否一致
                        if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getTotalInventoryQty()) > 0) {
                            // 拣货明细行拆单处理,拆单的同时出库预占同时拆分
                            WaveStorageDO newWaveStorageDO = new WaveStorageDO();
                            BeanUtils.copyProperties(waveStorageDO, newWaveStorageDO);
                            String waveStorageId = String.valueOf(SnowFlakeUtils.getId());
                            newWaveStorageDO.setId(waveStorageId);
                            newWaveStorageDO.setQty(infTaskOutBackDTO.getTotalInventoryQty());
                            // newWaveStorageDO.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            waveStorageDO.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getTotalInventoryQty()));

                            PickTaskD newPickTaskD = new PickTaskD();
                            BeanUtils.copyProperties(pickTaskD, newPickTaskD);
                            newPickTaskD.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
                            newPickTaskD.setQty(infTaskOutBackDTO.getTotalInventoryQty());
                            newPickTaskD.setSrcPickTaskDId(pickTaskD.getPickTaskDId());
                            // newPickTaskD.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            newPickTaskD.setWaveStorageId(waveStorageId);
                            newPickTaskD.setObMsgId(infTaskOutBackDTO.getMsgId());
                            pickTaskD.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getTotalInventoryQty()));

                            // 插入和更新
                            waveStorageMapper.save(newWaveStorageDO);
                            waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("qty", waveStorageDO.getQty()).getMap(), WaveStorageDO.class);
                            pickTaskDMapper.save(newPickTaskD);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("qty", pickTaskD.getQty()).getMap(), PickTaskD.class);
                        } else if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getTotalInventoryQty()) == 0) {
                            // 说明出库数量就是需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage)容器号等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("obMsgId", infTaskOutBackDTO.getMsgId()).getMap(), PickTaskD.class);
                            // waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);
                        } else {
                            // 说明出库数量多余需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage,stockPre)容器号及货位等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("obMsgId", infTaskOutBackDTO.getMsgId()).getMap(), PickTaskD.class);
                            // waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);
                        }

                        // 说明是周转框,更新任务头,更新containerNo到任务明细行
                        PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
                        pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("status", "2").put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), PickTaskH.class);
                        pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("pickQty", infTaskOutBackDTO.getTotalInventoryQty()).put("pickTime", new Date()).put("flowStatus", "3").getMap(), PickTaskD.class);
                        // 自动拣货确认扣减库存
                        log.info("开始扣减库存");

                        InvStockPartCheckOut invStockCheck = new InvStockPartCheckOut();
                        invStockCheck.setQty(infTaskOutBackDTO.getTotalInventoryQty());
                        invStockCheck.setLocatorId(waveStorageDO.getLocatorId());
                        invStockCheck.setItemId(waveStorageDO.getItemId());
                        invStockCheck.setLineBillIds(new String[]{waveStorageDO.getBillDId()});
                        invStockCheck.setBatchNum(waveStorageDO.getBatchNum());
                        // invStockCheck.setContainerCode(infTaskOutBackDTO.getContainerNo());
                        RestMessage restMessage = invClient.outPartStockCheck(invStockCheck);
                        log.info("请求参数：{}", JSONObject.toJSONString(invStockCheck));
                        if (!restMessage.isSuccess()) {
                            throw new BizException("扣减库存失败: " + restMessage.getMessage() + String.format("，入参为：[仓库：%s][订单编号：%s]", waveStorageDO.getWarehouseId(), JSONObject.toJSONString(invStockCheck)));
                        }
                        log.info("扣减库存成功");

                        // 整个订单完成,回传状态；
                        orderOutboundStatusBackService.sendOutboundOrderStatusOms(pickTaskH.getBillGroupId(), "", "", "", "", "30", BigDecimal.ZERO);

                        BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                        infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                        infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                        infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                        infTaskOutBackVO.setQty(infTaskOutBackDTO.getTotalInventoryQty());
                        infTaskOutBackVO.setOuttype("3");
                    } else {
                        BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                        infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                        infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                        infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                        // 判断拣货数量是否一致
                        if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getQty()) > 0) {
                            // 拣货明细行拆单处理,拆单的同时出库预占同时拆分
                            WaveStorageDO newWaveStorageDO = new WaveStorageDO();
                            BeanUtils.copyProperties(waveStorageDO, newWaveStorageDO);
                            String waveStorageId = String.valueOf(SnowFlakeUtils.getId());
                            newWaveStorageDO.setId(waveStorageId);
                            newWaveStorageDO.setQty(infTaskOutBackDTO.getQty());
                            newWaveStorageDO.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            waveStorageDO.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getQty()));

                            PickTaskD newPickTaskD = new PickTaskD();
                            BeanUtils.copyProperties(pickTaskD, newPickTaskD);
                            newPickTaskD.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
                            newPickTaskD.setQty(infTaskOutBackDTO.getQty());
                            newPickTaskD.setSrcPickTaskDId(pickTaskD.getPickTaskDId());
                            newPickTaskD.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            newPickTaskD.setWaveStorageId(waveStorageId);
                            newPickTaskD.setObMsgId(infTaskOutBackVO.getMsgId());
                            pickTaskD.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getQty()));

                            // 插入和更新
                            waveStorageMapper.save(newWaveStorageDO);
                            waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("qty", waveStorageDO.getQty()).getMap(), WaveStorageDO.class);
                            pickTaskDMapper.save(newPickTaskD);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("qty", pickTaskD.getQty()).getMap(), PickTaskD.class);

                            infTaskOutBackVO.setOuttype("2");
                        } else if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getQty()) == 0) {
                            // 说明出库数量就是需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage)容器号等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);

                            infTaskOutBackVO.setOuttype("1");
                        } else {
                            // 说明出库数量多余需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage,stockPre)容器号及货位等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);

                            infTaskOutBackVO.setOuttype("1");
                        }
                    }
                    saveList.add(infTaskOutBackVO);
                    if (infTaskOutBackVO.getWorkType().equals("50")) {
                        // 补货任务同步更新预占的托盘号
                        UpdateLocatorVo vo = new UpdateLocatorVo();
                        vo.setLineBillId(waveStorageDO.getBillDId());
                        vo.setContainerCode(infTaskOutBackDTO.getContainerNo());
                        RestMessage<String> msg = invClient.updateContainerCode(Collections.singletonList(vo));
                        if (!msg.isSuccess()) {
                            throw new BizException("补货任务更新出库托盘号异常!" + msg.getMessage());
                        }
                    }
                } else if (infTaskOutBackDTO.getWorkType().equals("20")) {
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    moveList.add(infTaskOutBackVO);
                    saveList.add(infTaskOutBackVO);
                } else if (infTaskOutBackDTO.getWorkType().equals("30")) {
                    // 盘点出库回告信息 ==> 2023-02-20 文档修改为 totalInventoryQty
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                    infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                    infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                    infTaskOutBackVO.setQty(infTaskOutBackDTO.getInventoryQty());
                    infTaskOutBackVO.setExtend04(infTaskOutBackDTO.getCountQty() != null ? infTaskOutBackDTO.getCountQty().toString() : Convert.toStr(infTaskOutBackDTO.getTotalInventoryQty(), ""));
                    infTaskOutBackVO.setOuttype("4");
                    saveList.add(infTaskOutBackVO);

                    invCheckList.add(infTaskOutBackDTO);
                    log.info("盘点出库回告信息");
                } else if (infTaskOutBackDTO.getWorkType().equals("40")) {
                    // 养护出库回告信息
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                    infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                    infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                    infTaskOutBackVO.setQty(infTaskOutBackDTO.getInventoryQty());
                    infTaskOutBackVO.setExtend04(infTaskOutBackDTO.getTotalInventoryQty() == null ? null : infTaskOutBackDTO.getTotalInventoryQty().toString());
                    infTaskOutBackVO.setOuttype("5");
                    saveList.add(infTaskOutBackVO);

                    infTaskOutBackDTO.setBackType("1");//回告类型 1：四向拖盘回告
                    upkeepList.add(infTaskOutBackDTO);
                    log.info("养护出库回告信息");
                }
            }
            if (CollectionUtil.isNotEmpty(moveList)) {
                // 移库任务,扣减库存
                String[] lineIds = moveList.stream().map(InfTaskOutBackVO::getSeqNo).toArray(String[]::new);
                if (lineIds.length > 0) {
                    // 移库确认
                    MoveConfirmParamsVO vo = new MoveConfirmParamsVO();
                    vo.setMoveFlag(2);
                    vo.setLineIds(lineIds);
                    RestMessage msg = operateResource.confirmMove(vo);
                    if (!msg.isSuccess()) {
                        throw new BizException("移库回告失败！" + msg.getMessage());
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(upkeepList)) {
                RestMessage restMessage = gspResource.gspUpKeepOutBack(upkeepList);
                if (!restMessage.isSuccess()) {
                    throw new BizException("养护回告失败！" + restMessage.getMessage());
                }
            }
            if (CollectionUtil.isNotEmpty(invCheckList)) {
                RestMessage<Object> restMessage = operateResource.invCheckOutBack(invCheckList);
                if (!restMessage.isSuccess()) {
                    throw new BizException("盘点回告失败！" + restMessage.getMessage());
                }
            }
            // 保存回告任务信息;
            if (CollUtil.isNotEmpty(saveList)) {
                wmsTaskOutBackMapper.saveBatch(saveList);
            }
            // 保存回告任务信息;
            if (CollUtil.isNotEmpty(updateList)) {
                for (InfTaskOutBackVO outBackVO : updateList) {
                    wmsTaskOutBackMapper.updateMapById(outBackVO.getMsgId(), MapUtils.put("extend03", backBatch).getMap(), InfTaskOutBackVO.class);
                }
            }
            log.info("出库回告任务成功");
        } else {
            return new RestMessage(false, "500", "EIS出库回传WMS失败,数据为空", infTaskOutBackDTOList);
        }
        return new RestMessage(true, "200", "WMS接受拣选任务成功！", infTaskOutBackDTOList);
    }

    /**
     * 提供出库任务回告接口给EIS
     *
     * @param infTaskOutBackDTOList infTaskOutBackDTOList
     * @return RestMessage<?> rest
     */
    @Override
    @InterfaceMethod(key = "infTaskOutBackAgvL", name = "AGV货架回告", type = InterfaceType.Send)
    public RestMessage<List<InfTaskOutBackDTO>> infTaskOutBackAgvL(List<InfTaskOutBackDTO> infTaskOutBackDTOList) {
        if (CollectionUtil.isNotEmpty(infTaskOutBackDTOList)) {
            List<InfTaskOutBackVO> saveList = new ArrayList<>();
            List<InfTaskOutBackVO> moveList = new ArrayList<>(); // 移库任务
            List<InfTaskOutBackDTO> upkeepList = new ArrayList<>();//养护任务
            List<InfTaskOutBackDTO> invCheckList = new ArrayList<>();//盘点任务
            InfTaskOutBackVO infTaskOutBackVO = null;
            InfTaskOutBackDTO taskOutBackDTO = infTaskOutBackDTOList.get(0);
            String locationNo = taskOutBackDTO.getLocationNo();
            String pickOrderId = String.valueOf(SnowFlakeUtils.getId());
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.MINUTE, new Random().nextInt(15) + 15);
            if (!StringUtils.isBlank(locationNo)) {
                // 说明为周转框回告,生成拣选单并自动完成
                PickTaskD pickTaskD = pickTaskDMapper.findById(taskOutBackDTO.getSeqNo(), PickTaskD.class);
                if (null == pickTaskD) {
                    return new RestMessage(false, "500", "EIS出库回传WMS失败,任务不存在", infTaskOutBackDTOList);
                }
                // 根据msgId判断此条数据是否已接收并处理
                InfTaskOutBackVO taskOutBackVO = wmsTaskOutBackMapper.findById(taskOutBackDTO.getMsgId(), InfTaskOutBackVO.class);
                if (null != taskOutBackVO) {
                    log.info("数据已处理,无需要在次处理,任务号:{}", taskOutBackDTO.getSeqNo());
                } else {
                    if (!StringUtils.isBlank(pickTaskD.getFlowStatus()) && !pickTaskD.getFlowStatus().equals("3")) {
                        PickOrder pickOrder = new PickOrder();
                        pickOrder.setPickOrderId(pickOrderId);
                        pickOrder.setEnterpriseId(pickTaskD.getEnterpriseId());
                        pickOrder.setStatus("2");
                        pickOrder.setWarehouseId(taskOutBackDTO.getWarehouseId());
                        pickOrder.setTaskCount(infTaskOutBackDTOList.size());
                        pickOrder.setOperatorId(pickTaskD.getCreator());
                        pickOrder.setOperatorName(pickTaskD.getCreatorName());
                        pickOrder.setOperatorCode(pickTaskD.getCreatorName());
                        pickOrder.setPickTaskType(1); // 周转框零货
                        pickOrder.setPrintStatus("1");
                        pickOrder.setEnterpriseId(pickTaskD.getEnterpriseId());
                        pickOrder.setGmtCreate(calendar.getTime());
                        pickOrder.setGmtModified(calendar.getTime());
                        pickOrderMapper.save(pickOrder);
                    }
                }
            }
            for (InfTaskOutBackDTO infTaskOutBackDTO : infTaskOutBackDTOList) {
                // 根据msgId判断此条数据是否已接收并处理
                InfTaskOutBackVO taskOutBackVO = wmsTaskOutBackMapper.findById(infTaskOutBackDTO.getMsgId(), InfTaskOutBackVO.class);
                if (null != taskOutBackVO) {
                    log.info("数据已处理,无需要在次处理,任务号:{}", infTaskOutBackDTO.getSeqNo());
                    continue;
                }
                infTaskOutBackVO = new InfTaskOutBackVO();
                if (null != infTaskOutBackDTO.getWorkType() && infTaskOutBackDTO.getWorkType().equals("10")) {
                    // 根据seqno判断任务是否存在
                    PickTaskD pickTaskD = pickTaskDMapper.findById(infTaskOutBackDTO.getSeqNo(), PickTaskD.class);
                    if (null == pickTaskD) {
                        return new RestMessage(false, "500", "EIS出库回传WMS失败,任务不存在", infTaskOutBackDTOList);
                    }
                    // 判断是否为周转框回告
                    if (!StringUtils.isBlank(infTaskOutBackDTO.getLocationNo())) {
                        if (!StringUtils.isBlank(pickTaskD.getFlowStatus()) && pickTaskD.getFlowStatus().equals("3")) {
                            log.info("数据已处理,无需要在次处理,任务号:{}", infTaskOutBackDTO.getSeqNo());
                            continue;
                        }
                        WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                        // 判断拣货数量是否一致
                        if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getInventoryQty()) > 0) {
                            // 拣货明细行拆单处理,拆单的同时出库预占同时拆分
                            WaveStorageDO newWaveStorageDO = new WaveStorageDO();
                            BeanUtils.copyProperties(waveStorageDO, newWaveStorageDO);
                            String waveStorageId = String.valueOf(SnowFlakeUtils.getId());
                            newWaveStorageDO.setId(waveStorageId);
                            newWaveStorageDO.setQty(infTaskOutBackDTO.getInventoryQty());
                            newWaveStorageDO.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            waveStorageDO.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getInventoryQty()));

                            PickTaskD newPickTaskD = new PickTaskD();
                            BeanUtils.copyProperties(pickTaskD, newPickTaskD);
                            newPickTaskD.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
                            newPickTaskD.setQty(infTaskOutBackDTO.getInventoryQty());
                            newPickTaskD.setSrcPickTaskDId(pickTaskD.getPickTaskDId());
                            newPickTaskD.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            newPickTaskD.setWaveStorageId(waveStorageId);
                            newPickTaskD.setObMsgId(infTaskOutBackVO.getMsgId());
                            pickTaskD.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getInventoryQty()));

                            // 插入和更新
                            waveStorageMapper.save(newWaveStorageDO);
                            waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("qty", waveStorageDO.getQty()).getMap(), WaveStorageDO.class);
                            pickTaskDMapper.save(newPickTaskD);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("qty", pickTaskD.getQty()).getMap(), PickTaskD.class);
                        } else if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getInventoryQty()) == 0) {
                            // 说明出库数量就是需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage)容器号等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);
                        } else {
                            // 说明出库数量多余需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage,stockPre)容器号及货位等
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);
                        }

                        // 说明是周转框,更新任务头,更新containerNo到任务明细行,需要判断任务头是否已更新。并且相等。如果不是需要拆分h表
                        PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
                        if (StrUtil.isBlank(pickTaskH.getContainerCode())) {
                            pickTaskHMapper.updateMapById(pickTaskH.getPickTaskId(), MapUtils.put("status", "2").put("pickOrderId", pickOrderId).put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), PickTaskH.class);
                        } else {
                            // 容器号不为空判断是否相等,不相等则更新,相等则不处理
                            if (!pickTaskH.getContainerCode().equals(infTaskOutBackDTO.getContainerNo())) {
                                // 不相等,拆分pickTaskH
                                PickTaskH newPickTaskH = new PickTaskH();
                                String newPickTaskId = String.valueOf(SnowFlakeUtils.getId());
                                BeanUtils.copyProperties(pickTaskH, newPickTaskH);
                                newPickTaskH.setPickTaskId(newPickTaskId);
                                newPickTaskH.setPickOrderId(pickOrderId);
                                newPickTaskH.setContainerCode(infTaskOutBackDTO.getContainerNo());
                                pickTaskHMapper.save(newPickTaskH);
                                pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("pickTaskId", newPickTaskId).getMap(), PickTaskD.class);
                            }
                        }

                        pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("pickQty", infTaskOutBackDTO.getInventoryQty()).put("pickTime", new Date()).put("flowStatus", "3").getMap(), PickTaskD.class);
                        // 自动拣货确认扣减库存
                        log.info("开始扣减库存");

                        InvStockPartCheckOut invStockCheck = new InvStockPartCheckOut();
                        invStockCheck.setQty(infTaskOutBackDTO.getInventoryQty());
                        invStockCheck.setLocatorId(waveStorageDO.getLocatorId());
                        invStockCheck.setItemId(waveStorageDO.getItemId());
                        invStockCheck.setLineBillIds(new String[]{waveStorageDO.getBillDId()});
                        invStockCheck.setBatchNum(waveStorageDO.getBatchNum());
                        invStockCheck.setContainerCode(infTaskOutBackDTO.getContainerNo());
                        RestMessage restMessage = invClient.outPartStockCheck(invStockCheck);
                        log.info("请求参数：{}", JSONObject.toJSONString(invStockCheck));
                        if (!restMessage.isSuccess()) {
                            throw new BizException("扣减库存失败: " + restMessage.getMessage() + String.format("，入参为：[仓库：%s][订单编号：%s]", waveStorageDO.getWarehouseId(), JSONObject.toJSONString(invStockCheck)));
                        }
                        log.info("扣减库存成功");

                        // 整个订单完成,回传状态；
                        orderOutboundStatusBackService.sendOutboundOrderStatusOms(pickTaskH.getBillGroupId(), "", "", "", "", "30", BigDecimal.ZERO);

                        BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                        infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                        infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                        infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                        infTaskOutBackVO.setQty(infTaskOutBackDTO.getInventoryQty());
                        infTaskOutBackVO.setOuttype("3");

                        // 占用容器
                        this.usedContainer(infTaskOutBackDTO.getContainerNo(), infTaskOutBackDTO.getWarehouseId());
                    } else {
                        BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                        infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                        infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                        infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                        // 判断拣货数量是否一致
                        if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getQty()) > 0) {
                            // 拣货明细行拆单处理,拆单的同时出库预占同时拆分
                            WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                            WaveStorageDO newWaveStorageDO = new WaveStorageDO();
                            BeanUtils.copyProperties(waveStorageDO, newWaveStorageDO);
                            String waveStorageId = String.valueOf(SnowFlakeUtils.getId());
                            newWaveStorageDO.setId(waveStorageId);
                            newWaveStorageDO.setQty(infTaskOutBackDTO.getQty());
                            newWaveStorageDO.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            waveStorageDO.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getQty()));

                            PickTaskD newPickTaskD = new PickTaskD();
                            BeanUtils.copyProperties(pickTaskD, newPickTaskD);
                            newPickTaskD.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
                            newPickTaskD.setQty(infTaskOutBackDTO.getQty());
                            newPickTaskD.setSrcPickTaskDId(pickTaskD.getPickTaskDId());
                            newPickTaskD.setContainerCode(infTaskOutBackDTO.getContainerNo());
                            newPickTaskD.setWaveStorageId(waveStorageId);
                            newPickTaskD.setObMsgId(infTaskOutBackVO.getMsgId());
                            pickTaskD.setQty(pickTaskD.getQty().subtract(infTaskOutBackDTO.getQty()));

                            // 插入和更新
                            waveStorageMapper.save(newWaveStorageDO);
                            waveStorageMapper.updateMapById(pickTaskD.getWaveStorageId(), MapUtils.put("qty", waveStorageDO.getQty()).getMap(), WaveStorageDO.class);
                            pickTaskDMapper.save(newPickTaskD);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("qty", pickTaskD.getQty()).getMap(), PickTaskD.class);

                            infTaskOutBackVO.setOuttype("2");
                        } else if (pickTaskD.getQty().compareTo(infTaskOutBackDTO.getQty()) == 0) {
                            // 说明出库数量就是需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage)容器号等
                            WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);

                            infTaskOutBackVO.setOuttype("1");
                        } else {
                            // 说明出库数量多余需要拣货的数量,不需要拆单,只需要直接更新(d,waveStorage,stockPre)容器号及货位等
                            WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                            pickTaskDMapper.updateMapById(pickTaskD.getPickTaskDId(), MapUtils.put("srcPickTaskDId", pickTaskD.getPickTaskDId()).put("containerCode", infTaskOutBackDTO.getContainerNo()).put("obMsgId", infTaskOutBackVO.getMsgId()).getMap(), PickTaskD.class);
                            waveStorageMapper.updateMapById(waveStorageDO.getId(), MapUtils.put("containerCode", infTaskOutBackDTO.getContainerNo()).getMap(), WaveStorageDO.class);

                            infTaskOutBackVO.setOuttype("1");
                        }
                    }
                    saveList.add(infTaskOutBackVO);
                } else if (infTaskOutBackDTO.getWorkType().equals("20")) {
                    // moveList.add(infTaskOutBackVO);
                } else if (infTaskOutBackDTO.getWorkType().equals("30")) {
                    // 盘点出库回告信息
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                    infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                    infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                    infTaskOutBackVO.setQty(infTaskOutBackDTO.getInventoryQty());
                    infTaskOutBackVO.setExtend04(infTaskOutBackDTO.getCountQty() != null ? infTaskOutBackDTO.getCountQty().toString() : infTaskOutBackDTO.getInventoryQty().toString());
                    infTaskOutBackVO.setOuttype("4");
                    saveList.add(infTaskOutBackVO);

                    infTaskOutBackDTO.setBackType("2"); //回告类型 2：货架回告
                    invCheckList.add(infTaskOutBackDTO);
                    log.info("盘点出库回告信息");
                } else if (infTaskOutBackDTO.getWorkType().equals("40")) {
                    // 养护出库回告信息
                    BeanUtils.copyProperties(infTaskOutBackDTO, infTaskOutBackVO);
                    infTaskOutBackVO.setMsgId(String.valueOf(SnowFlakeUtils.getId()));
                    infTaskOutBackVO.setItemId(infTaskOutBackDTO.getItemId());
                    infTaskOutBackVO.setLotId(infTaskOutBackDTO.getLotId());
                    infTaskOutBackVO.setQty(infTaskOutBackDTO.getInventoryQty());
                    infTaskOutBackVO.setExtend04(infTaskOutBackDTO.getCountQty() != null ? infTaskOutBackDTO.getCountQty().toString() : infTaskOutBackDTO.getInventoryQty().toString());
                    infTaskOutBackVO.setOuttype("5");
                    saveList.add(infTaskOutBackVO);

                    infTaskOutBackDTO.setBackType("2");//回告类型 2：货架回告
                    upkeepList.add(infTaskOutBackDTO);
                    log.info("养护出库回告信息");
                }
            }
            if (CollectionUtil.isNotEmpty(moveList)) {
                // 移库任务,扣减库存
                String[] lineIds = moveList.stream().map(InfTaskOutBackVO::getSeqNo).toArray(String[]::new);
                if (lineIds.length > 0) {
                    // 移库确认
                    InvStockCheckMove invStockCheckMove = new InvStockCheckMove();
                    invStockCheckMove.setMoveFlag(0);
                    invStockCheckMove.setLineBillIds(lineIds);
                    RestMessage invResult = invClient.moveStockCheck(invStockCheckMove);
                    if (!invResult.isSuccess()) {
                        throw new BizException(invResult.getMessage());
                    }
                }
            }
            if (CollectionUtil.isNotEmpty(upkeepList)) {
                gspResource.gspUpKeepOutBack(upkeepList);
            }
            if (CollectionUtil.isNotEmpty(invCheckList)) {
                operateResource.invCheckOutBack(invCheckList);
            }
            // 保存回告任务信息;
            if (CollUtil.isNotEmpty(saveList)) {
                wmsTaskOutBackMapper.saveBatch(saveList);
            }
            log.info("出库回告任务成功");
        } else {
            return new RestMessage(false, "500", "EIS出库回传WMS失败,数据为空", infTaskOutBackDTOList);
        }
        return new RestMessage(true, "200", "WMS接受拣选任务成功！", infTaskOutBackDTOList);
    }

    /**
     * 提供容器校验接口给EIS
     *
     * @param containerNoList containerNoList
     * @return RestMessage<?> rest
     */
    @Override
    public RestMessage<List<ValidateContainerNoDTO>> validateContainerNoList(List<ValidateContainerNoDTO> containerNoList) {
        // 用于存放校验未通过的容器集合
        List<ValidateContainerNoDTO> errorList = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(containerNoList)) {
            for (ValidateContainerNoDTO vo : containerNoList) {
                ContainerQueryVO queryVO = new ContainerQueryVO();
                queryVO.setContainerCode(vo.getContainerNo());
                RestMessage<Boolean> restMessage = warehouseResource.isEnable(queryVO);
                if (!restMessage.isSuccess()) {
                    log.info("容器占用接口调用失败");
                }
                boolean isEnable = restMessage.getData();
                if (!isEnable) {
                    vo.setErrorMsg("播种容器不可用");
                    errorList.add(vo);
                }
            }
        } else {
            return new RestMessage(false, "500", "EIS容器校验失败,数据为空", null);
        }
        if (CollectionUtil.isNotEmpty(errorList)) {
            return new RestMessage(true, "200", "请求成功", errorList);
        } else {
            return new RestMessage(true, "200", "请求成功", new ArrayList<ValidateContainerNoDTO>());
        }
    }

    @Override
    public Page<RePrintWholeDto> taskListForPrintAgain(PrintAgainVo printAgainVo) {
        PageHelper.startPage(printAgainVo.getPageNum(), printAgainVo.getPageSize());
        List<RePrintWholeDto> printDtos = pickTaskDMapper.listPrintTask(printAgainVo);
        return PageUtils.getPage(printDtos);
    }

    /**
     * 补打整件列表
     *
     * @param printAgainVo
     * @return 以标签的维度进行查询
     */
    @Override
    public Page<RePrintWholeDto> listWholeLabelRepair(PrintAgainVo printAgainVo) {
        UserDTO userDTO = userTemplate.getUserDTO();
        printAgainVo.setEnterpriseId(userDTO.getEnterpriseId());
        PageHelper.startPage(printAgainVo.getPageNum(), printAgainVo.getPageSize());
        List<RePrintWholeDto> printDtos = pickTaskDMapper.listWholeLabelRepair(printAgainVo);
        Page<RePrintWholeDto> result = PageUtils.getPage(printDtos);
        // 查询结果中货主无值， 查询货主信息并组装
        if (CollUtil.isNotEmpty(result.getList())) {
            Set<String> consignorIdSet = new HashSet<>();
            Set<String> shipper1 = new HashSet<>();
            Set<String> shipper2 = new HashSet<>();
            for (RePrintWholeDto rePrintWholeDto : result.getList()) {
                consignorIdSet.add(rePrintWholeDto.getConsignorId());
                if (StrUtil.isNotEmpty(rePrintWholeDto.getShipperId())) {
                    if (rePrintWholeDto.getShipperType() == null || !rePrintWholeDto.getShipperType().equals("1")) {
                        shipper2.add(rePrintWholeDto.getShipperId());
                    } else {
                        shipper1.add(rePrintWholeDto.getShipperId());
                    }
                }
            }
            List<BaseCargoOwnerMst> cargoOwnerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(consignorIdSet)) {
                RestMessage<Map<String, BaseCargoOwnerMst>> cargoMsg = chainResource.getCargoOwnerByIds(consignorIdSet);
                if (cargoMsg != null && CollUtil.isNotEmpty(cargoMsg.getData())) {
                    for (String s : cargoMsg.getData().keySet()) {
                        cargoOwnerMsts.add(cargoMsg.getData().get(s));
                    }
                }
            }
            List<BaseCustomerMst> customerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper2)) {
                BaseCustomerMstRequestVO vo = new BaseCustomerMstRequestVO();
                vo.setEnterpriseid(printAgainVo.getEnterpriseId());
                vo.setIncludeSearchIds(shipper2);
                // 2 代表客户
                RestMessage<List<BaseCustomerMst>> restMessage = chainResource.findAll(vo);
                if (restMessage.isSuccess() && CollUtil.isNotEmpty(restMessage.getData())) {
                    customerMsts = restMessage.getData();
                }
            }
            List<BaseSupplierMst> supplierMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper1)) {
                // 查询供应商
                RestMessage<Map<String, BaseSupplierMst>> supplierMst = chainResource.getSupplierMstByIds(shipper1);
                if (supplierMst.isSuccess() && CollUtil.isNotEmpty(supplierMst.getData())) {
                    for (String s : supplierMst.getData().keySet()) {
                        supplierMsts.add(supplierMst.getData().get(s));
                    }
                }
            }
            for (RePrintWholeDto rePrintWholeDto : result.getList()) {
                for (BaseCargoOwnerMst cargoOwnerMst : cargoOwnerMsts) {
                    if (cargoOwnerMst.getCargoOwnerId().equals(rePrintWholeDto.getConsignorId())) {
                        rePrintWholeDto.setConsignorName(cargoOwnerMst.getCargoOwnerName());
                        rePrintWholeDto.setConsignorCode(cargoOwnerMst.getCargoOwnerCode());
                        break;
                    }
                }
                if (rePrintWholeDto.getShipperType() == null || !rePrintWholeDto.getShipperType().equals("1")) {
                    for (BaseCustomerMst customerMst : customerMsts) {
                        if (customerMst.getCustomerId().equals(rePrintWholeDto.getShipperId())) {
                            rePrintWholeDto.setShipperCode(customerMst.getCustomerCode());
                            rePrintWholeDto.setShipperName(customerMst.getCustomerName());
                        }
                    }
                } else {
                    for (BaseSupplierMst supplierMst : supplierMsts) {
                        if (supplierMst.getSupplierId().equals(rePrintWholeDto.getShipperId())) {
                            rePrintWholeDto.setShipperCode(supplierMst.getSupplierCode());
                            rePrintWholeDto.setShipperName(supplierMst.getSupplierName());
                        }
                    }
                }
                //计算件数和零散数 暂时取计划数量
                if (StrUtil.isNotEmpty(rePrintWholeDto.getConversionRate())) {
                    rePrintWholeDto.setPcs(rePrintWholeDto.getQty().divide(new BigDecimal(rePrintWholeDto.getConversionRate()), 0, RoundingMode.HALF_UP));
                    rePrintWholeDto.setOdd(BigDecimal.ZERO);
                } else {
                    rePrintWholeDto.setPcs(rePrintWholeDto.getQty());
                    rePrintWholeDto.setOdd(BigDecimal.ZERO);
                }
            }
        }
        return result;
    }

    //根据barcodeId进行打印
    @Override
    public List<PrintDataWithMark> wholeLabelRepairPrint(PrintAgainVo printAgainVo) {
        if (CollUtil.isEmpty(printAgainVo.getIds())) {
            throw new PrologException("ids不能为空！");
        }
        if (StrUtil.isEmpty(printAgainVo.getEnterpriseId())) {
            printAgainVo.setEnterpriseId(userTemplate.getUserDTO().getEnterpriseId());
        }
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        List<Map<String, Object>> whole = pickTaskHMapper.wholeLabelRepairPrint(printAgainVo.getIds(), printAgainVo.getWarehouseId(), printAgainVo.getEnterpriseId());
        ;
        List<Map<String, Object>> replenish = pickTaskHMapper.replenishLabelRepairPrint(printAgainVo.getIds(), printAgainVo.getWarehouseId(), printAgainVo.getEnterpriseId());
        if (CollUtil.isNotEmpty(whole)) {
            List<ReportData> reportDatas = new ArrayList<>();
            PrintData printData = new PrintData();
            printData.setPrintName("");
            Set<String> itemIds = whole.stream().map(var -> (String) var.get("itemId")).collect(Collectors.toSet());
            RestMessage<List<BaseMtlItemMst>> itemMsg = itemClient.getListByIds(itemIds);
            for (Map<String, Object> map : whole) {
                Map<String, Object> head = new HashMap<>();
                // 公共字段
                BaseMtlItemMst itemInfoVO = itemMsg.getData().stream().filter(var -> var.getItemId().equals(map.get("itemId"))).findFirst().orElse(null);
                head.put("conversionRate", null == itemInfoVO ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() == null ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() + itemInfoVO.getCaseUom());
                head.put("itemName", map.get("SPMCH")); // 商品名称
                head.put("barcode", map.get("id")); // 条码/二维码==>barcode_d的id
                head.put("box", map.get("container_code")); // 箱号/数量
                head.put("itemCode", map.get("itemcode") == null ? map.get("SPBH") : map.get("itemcode")); // 商品code
                head.put("manufacturer", map.get("SHENGCCJ")); // 生产厂家
                head.put("qty", map.get("Z_QTY")); // 明细数量
                head.put("packUnits", map.get("SHPGG")); // 商品规格
                head.put("uom", map.get("DW")); // 单位
                head.put("remark", map.get("REMARK")); // 备注
                head.put("lotNo", map.get("PH")); // 批号
                head.put("productionDate", map.get("P_DATE_S")); // 生产日期
                head.put("expiredDate", map.get("E_DATE_S")); // 有效期至
                String workStageCodes = getStage((String) map.get("DJBHQ"));
                if (workStageCodes != null) {
                    head.put("ZCQQSH", workStageCodes);
                } else {
                    head.put("ZCQQSH", "机动");
                }
                head.put("CPH", ((BigDecimal) map.get("print_cnt")).compareTo(BigDecimal.ZERO) > 0 ? "重" : ""); // 重打标志，例:   重
                // 拣货标签特有
                head.put("psfx", map.get("PSFX")); // 配送方向
                head.put("billid", map.get("billid")); // 订单id
                head.put("locatorCode", map.get("LOCATOR_CODE")); // 货位
                head.put("checkName", map.get("FHR1")); // 拣货员
                head.put("kpy", map.get("YWY"));
                head.put("receiveAddress", map.get("DW_DZ"));
                head.put("lxr", map.get("lxr"));
                head.put("tel", map.get("lxfs"));
                head.put("shipperCode", map.get("shipperCode"));
                head.put("shipperName", map.get("shipperName"));
                ReportData reportData = new ReportData();
                reportData.setHead(head);
                reportDatas.add(reportData);
                barcodeDMapper.updateMapById(map.get("id"), MapUtils.put("printCnt", ((BigDecimal) map.get("print_cnt")).intValue() + 1).getMap(), BarCodeDDO.class);
                if (map.get("PRINTSTATUS") != null && map.get("PRINTSTATUS").equals("0")) {
                    pickOrderMapper.updateMapById(map.get("PICKORDERID"), MapUtils.put("printStatus", "1").getMap(), PickOrder.class);
                }
            }
            printData.setData(reportDatas);
            printDataList.add(new PrintDataWithMark(printData, "0"));
        }

        if (CollUtil.isNotEmpty(replenish)) {
            List<ReportData> reportDatas = new ArrayList<>();
            PrintData printData = new PrintData();
            printData.setPrintName("");
            Set<String> itemIds = whole.stream().map(var -> (String) var.get("itemId")).collect(Collectors.toSet());
            RestMessage<List<BaseMtlItemMst>> itemMsg = itemClient.getListByIds(itemIds);
            for (Map<String, Object> map : whole) {
                Map<String, Object> head = new HashMap<>();
                // 公共字段
                BaseMtlItemMst itemInfoVO = itemMsg.getData().stream().filter(var -> var.getItemId().equals(map.get("itemId"))).findFirst().orElse(null);
                head.put("conversionRate", null == itemInfoVO ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() == null ? map.get("JLGG") : itemInfoVO.getCaseConversionRate() + itemInfoVO.getCaseUom());
                head.put("itemName", map.get("SPMCH")); // 商品名称
                head.put("barcode", map.get("id")); // 条码/二维码==>barcode_d的id
                head.put("box", map.get("container_code")); // 箱号/数量
                head.put("itemCode", map.get("itemcode") == null ? map.get("SPBH") : map.get("itemcode")); // 商品code
                head.put("manufacturer", map.get("SHENGCCJ")); // 生产厂家
                head.put("qty", map.get("Z_QTY")); // 明细数量
                head.put("packUnits", map.get("SHPGG")); // 商品规格
                head.put("uom", map.get("DW")); // 单位
                head.put("remark", map.get("REMARK")); // 备注
                head.put("lotNo", map.get("PH")); // 批号
                head.put("productionDate", map.get("P_DATE_S")); // 生产日期
                head.put("expiredDate", map.get("E_DATE_S")); // 有效期至
                head.put("CPH", ((BigDecimal) map.get("print_cnt")).compareTo(BigDecimal.ZERO) > 0 ? "重" : "");
                if (map.get("MOVETYPE") != null) {
                    switch ((String) map.get("MOVETYPE")) {
                        case "1":
                            head.put("taskType", "主动补货");
                            break;
                        case "2":
                            head.put("taskType", "紧急补货");
                            break;
                        case "3":
                            head.put("taskType", "波次补货");
                            break;
                        case "4":
                            head.put("taskType", "被动补货");
                            break;
                        default:
                            head.put("taskType", "");
                    }
                    head.put("pzwh", itemInfoVO.getBaseMtlItemHealth().getItemHealthApprovalNbr());
                    head.put("picker", map.get("CZR"));
                    head.put("billDate", map.get("gmt_create") == null ? DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_PATTERN) : DateUtil.format((Date) map.get("gmt_create"), DatePattern.PURE_DATE_PATTERN));
                    head.put("srcLocator", map.get("XSHW"));
                    head.put("destLocator", map.get("KB"));
                    head.put("billId", map.get("DJBHQ"));
                } else {
                    head.put("taskType", "补货");
                }
                ReportData reportData = new ReportData();
                reportData.setHead(head);
                reportDatas.add(reportData);
            }
            printData.setData(reportDatas);
            printDataList.add(new PrintDataWithMark(printData, "1"));
        }
        // 更新pick_task_d的打印次数
        pickTaskDMapper.updatePrintCountByBarcode(printAgainVo.getIds());
        // 更新barcoded的打印次数
        barcodeDMapper.updatePrintCountByBarcode(printAgainVo.getIds());
        return printDataList;
    }

    /**
     * 补打拼箱列表-明细
     *
     * @param
     * @return
     */
    @Override
    public List<RePrintBulkDetailDto> listSpellLabelDetailRepair(List<String> billNos) {
        if (CollUtil.isEmpty(billNos)) {
            return new ArrayList<>();
        }
        UserDTO userDTO = userTemplate.getUserDTO();

        List<RePrintBulkDetailDto> detailDtos = pickTaskDMapper.listSpellLabelDetailRepair(billNos);
        if (CollUtil.isEmpty(detailDtos)) {
            return new ArrayList<>();
        }
        Set<String> batchIds = detailDtos.stream().map(RePrintBulkDetailDto::getBatchId).collect(Collectors.toSet());
        // 获取批次信息
        RestMessage<List<BatchNumberListVO>> batchNumberBasicInfo = invClient.getBatchNumberBasicInfo(batchIds.toArray(new String[]{}));
        if (!batchNumberBasicInfo.isSuccess() || CollUtil.isEmpty(batchNumberBasicInfo.getData())) {
            throw new BizException("获取批次信息失败");
        }
        for (RePrintBulkDetailDto detailDto : detailDtos) {
            BatchNumberListVO batchNumberListVO = batchNumberBasicInfo.getData().stream().filter(var -> var.getBatchId().equals(detailDto.getBatchId())).findFirst().orElse(null);
            if (null == batchNumberListVO) {
                continue;
            }
            detailDto.setProductionPlace(batchNumberListVO.getProductionPlace());
        }
        return detailDtos;
    }

    @Override
    public List<PrintDataWithMark> printLcl(PrintAgainVo printAgainVo) {
        List<LclPrintDataDto> dataDtos = barcodeHMapper.ListDataByLclNo(printAgainVo.getIds(), printAgainVo.getBillNo());
        if (CollUtil.isEmpty(dataDtos)) {
            return new ArrayList<>();
        }
        Set<String> barcodeDIds = dataDtos.stream().map(LclPrintDataDto::getId).collect(Collectors.toSet());
        List<PrintDataWithMark> result = new ArrayList<>();
        RestMessage<List<BaseCommonDict>> shiplineidMsg = commonClient.getDictBasicListByCodes("common_shiplineid", null);
        List<InnerCheckTaskDV2VO> checkTaskDV2VOS = pickTaskDMapper.listPickTaskDByBarcodeDId(new ArrayList<>(barcodeDIds));
        Map<String, List<InnerCheckTaskDV2VO>> groupMap = checkTaskDV2VOS.stream().collect(Collectors.groupingBy(InnerCheckTaskDV2VO::getBarcodeDId));
        Set<String> itemIds = checkTaskDV2VOS.stream().map(InnerCheckTaskDV2VO::getItemId).collect(Collectors.toSet());
        RestMessage<List<BaseMtlItemMst>> itemMsg = itemClient.getListByIds(itemIds);
        Map<String, String> itemInfo = new HashMap<>();
        itemMsg.getData().forEach(var -> itemInfo.put(var.getItemId(), var.getItemName()));
        for (LclPrintDataDto dataDto : dataDtos) {
            List<InnerCheckTaskDV2VO> pickTaskDList = groupMap.get(dataDto.getId());
            if (CollUtil.isEmpty(pickTaskDList)) {
                continue;
            }
            Map<String, Object> head = new HashMap<>();
            head.put("barcode", dataDto.getId());
            head.put("lclNo", DateUtil.format(dataDto.getGmtCreate(), DatePattern.PURE_DATE_PATTERN) + "拼" + dataDto.getLclNo());
            head.put("zcq", dataDto.getWorkStageCode());
            head.put("psfx", dataDto.getLineName());
            head.put("CPH", (dataDto.getPrintCnt()).compareTo(0) > 0 ? "重" : "");
            head.put("billno", dataDto.getBillno());
            // 客户编号
            head.put("shipperCode", dataDto.getShipperCode());
            head.put("shipperName", dataDto.getShipperName());
            // 运输路线
            if (shiplineidMsg.isSuccess() && CollUtil.isNotEmpty(shiplineidMsg.getData())) {
                BaseCommonDict dict = shiplineidMsg.getData().stream().filter(var -> var.getDictCode().equals(dataDto.getShipLineId())).findFirst().orElse(null);
                if (null == dict) {
                    head.put("psfx", dataDto.getLineName());
                } else {
                    head.put("psfx", dict.getDictName());
                }
            }
            // 复核台
            head.put("fht", dataDto.getStationCode());
            // 收货地址
            head.put("receiveAddress", dataDto.getReceiveAddress());
            // 复核人
            head.put("checkName", dataDto.getCheckerName());
            // 联系人
            head.put("lxr", dataDto.getCustPerson());
            // 电话
            head.put("tel", dataDto.getCustPersonTel());
            // 备注
            head.put("remark", dataDto.getRemark());
            // 开票员
            head.put("kpy", dataDto.getSalespersonName());
            // 最大20行
            int maxLines = 20;
            List<ReportData> datas = new ArrayList<>();
            for (int i = 0; i < pickTaskDList.size() / 20 + 1; i++) {
                int subIndex = Math.min(maxLines, pickTaskDList.size() - maxLines * i);
                List<InnerCheckTaskDV2VO> subList = pickTaskDList.subList(i * maxLines, subIndex);
                List<Map<String, Object>> table = new ArrayList<>();
                ReportData data = new ReportData();
                for (InnerCheckTaskDV2VO taskDV2VO : subList) {
                    Map<String, Object> tableDetail = new HashMap<>();
                    tableDetail.put("itemname", itemInfo.get(taskDV2VO.getItemId()));
                    tableDetail.put("qty", null == taskDV2VO.getCheck2Qty() ? taskDV2VO.getCheckQty() : taskDV2VO.getCheck2Qty());
                    table.add(tableDetail);
                }
                data.setHead(head);
                data.setTable(table);
                datas.add(data);
            }
            PrintData printData = new PrintData();
            printData.setPrintName("");
            printData.setData(datas);
            result.add(new PrintDataWithMark(printData, "2"));
        }
        return result;
    }

    @Override
    public Page<RePrintBulkDto> listSpellLabelRepair(PrintAgainVo printAgainVo) {
        UserDTO userDTO = userTemplate.getUserDTO();
        printAgainVo.setEnterpriseId(userDTO.getEnterpriseId());
        PageHelper.startPage(printAgainVo.getPageNum(), printAgainVo.getPageSize());
        List<RePrintBulkDto> printDtos = pickTaskDMapper.listSpellLabelRepair(printAgainVo);
        Page<RePrintBulkDto> result = PageUtils.getPage(printDtos);
        // 查询结果中货主无值， 查询货主信息并组装
        if (CollUtil.isNotEmpty(result.getList())) {
            Set<String> consignorIdSet = new HashSet<>();
            Set<String> shipper1 = new HashSet<>();
            Set<String> shipper2 = new HashSet<>();
            for (RePrintBulkDto rePrintBulkDto : result.getList()) {
                consignorIdSet.add(rePrintBulkDto.getConsignorId());
                if (StrUtil.isNotEmpty(rePrintBulkDto.getShipperId())) {
                    if (rePrintBulkDto.getShipperType() == null || !rePrintBulkDto.getShipperType().equals("1")) {
                        shipper2.add(rePrintBulkDto.getShipperId());
                    } else {
                        shipper1.add(rePrintBulkDto.getShipperId());
                    }
                }
            }
            List<BaseCargoOwnerMst> cargoOwnerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(consignorIdSet)) {
                RestMessage<Map<String, BaseCargoOwnerMst>> cargoMsg = chainResource.getCargoOwnerByIds(consignorIdSet);
                if (cargoMsg != null && CollUtil.isNotEmpty(cargoMsg.getData())) {
                    for (String s : cargoMsg.getData().keySet()) {
                        cargoOwnerMsts.add(cargoMsg.getData().get(s));
                    }
                }
            }
            List<BaseCustomerMst> customerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper2)) {
                BaseCustomerMstRequestVO vo = new BaseCustomerMstRequestVO();
                vo.setEnterpriseid(printAgainVo.getEnterpriseId());
                vo.setIncludeSearchIds(shipper2);
                // 2 代表客户
                RestMessage<List<BaseCustomerMst>> restMessage = chainResource.findAll(vo);
                if (restMessage.isSuccess() && CollUtil.isNotEmpty(restMessage.getData())) {
                    customerMsts = restMessage.getData();
                }
            }
            List<BaseSupplierMst> supplierMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper1)) {
                // 查询供应商
                RestMessage<Map<String, BaseSupplierMst>> supplierMst = chainResource.getSupplierMstByIds(shipper1);
                if (supplierMst.isSuccess() && CollUtil.isNotEmpty(supplierMst.getData())) {
                    for (String s : supplierMst.getData().keySet()) {
                        supplierMsts.add(supplierMst.getData().get(s));
                    }
                }
            }
            for (RePrintBulkDto rePrintBulkDto : result.getList()) {
                for (BaseCargoOwnerMst cargoOwnerMst : cargoOwnerMsts) {
                    if (cargoOwnerMst.getCargoOwnerId().equals(rePrintBulkDto.getConsignorId())) {
                        rePrintBulkDto.setConsignorName(cargoOwnerMst.getCargoOwnerName());
                        rePrintBulkDto.setConsignorCode(cargoOwnerMst.getCargoOwnerCode());
                        break;
                    }
                }
                if (rePrintBulkDto.getShipperType() == null || !rePrintBulkDto.getShipperType().equals("1")) {
                    for (BaseCustomerMst customerMst : customerMsts) {
                        if (customerMst.getCustomerId().equals(rePrintBulkDto.getShipperId())) {
                            rePrintBulkDto.setShipperCode(customerMst.getCustomerCode());
                            rePrintBulkDto.setShipperName(customerMst.getCustomerName());
                        }
                    }
                } else {
                    for (BaseSupplierMst supplierMst : supplierMsts) {
                        if (supplierMst.getSupplierId().equals(rePrintBulkDto.getShipperId())) {
                            rePrintBulkDto.setShipperCode(supplierMst.getSupplierCode());
                            rePrintBulkDto.setShipperName(supplierMst.getSupplierName());
                        }
                    }
                }
            }
        }
        return result;
    }


    @Override
    public List<RePrintWholeBulkDetailDto> listWholeBulkDetailRepair(List<String> billIds) {
        if (CollUtil.isEmpty(billIds)) {
            return new ArrayList<>();
        }
        UserDTO userDTO = userTemplate.getUserDTO();
        List<RePrintWholeBulkDetailDto> detailDtos = pickTaskDMapper.listWholeBulkDetailRepair(billIds);
        if (CollUtil.isEmpty(detailDtos)) {
            return new ArrayList<>();
        }
        Set<String> batchIds = detailDtos.stream().map(RePrintWholeBulkDetailDto::getBatchId).collect(Collectors.toSet());
        // 获取批次信息
        RestMessage<List<BatchNumberListVO>> batchNumberBasicInfo = invClient.getBatchNumberBasicInfo(batchIds.toArray(new String[]{}));
        if (!batchNumberBasicInfo.isSuccess() || CollUtil.isEmpty(batchNumberBasicInfo.getData())) {
            throw new BizException("获取批次信息失败");
        }
        for (RePrintWholeBulkDetailDto detailDto : detailDtos) {
            BatchNumberListVO batchNumberListVO = batchNumberBasicInfo.getData().stream().filter(var -> var.getBatchId().equals(detailDto.getBatchId())).findFirst().orElse(null);
            if (null == batchNumberListVO) {
                continue;
            }
            detailDto.setProductionPlace(batchNumberListVO.getProductionPlace());
        }
        return detailDtos;
    }

    @Override
    public List<PrintDataWithMark> printAgainPaperSlip(PrintAgainVo printAgainVo) {
        if (CollUtil.isEmpty(printAgainVo.getIds())) {
            throw new BizException("请勾选需要打印的数据");
        }
        List<PickTaskDDTO> ddtos = pickTaskHMapper.getPickTaskByIds(printAgainVo.getIds());
        if (CollUtil.isEmpty(ddtos)) {
            return new ArrayList<>();
        }
        List<PrintDataWithMark> result = new ArrayList<>();
        // 通过pickOrder进行分组
        Map<String, List<PickTaskDDTO>> groupMap = ddtos.stream().collect(Collectors.groupingBy(PickTaskDDTO::getPickOrderId));
        for (String s : groupMap.keySet()) {
            //通过pick_order打印
            PrintData printData = new PrintData();
            PickOrder pickOrder = pickOrderMapper.findById(s, PickOrder.class);
            List<PickTaskDDTO> list = pickTaskHMapper.getPickTaskDList(null, null, s, printAgainVo.getWarehouseId());
            if (CollUtil.isEmpty(list)) {
                continue;
            }
            Map<String, Object> head = new HashMap<>();
            List<Map<String, Object>> tables = new ArrayList<>();
            ReportData reportData = new ReportData();
            BigDecimal totQty = BigDecimal.ZERO;
            BigDecimal totPcs = BigDecimal.ZERO;
            BigDecimal totOdd = BigDecimal.ZERO;
            ItemMstQueryVO vo = new ItemMstQueryVO();
            Set<String> itemIds = new HashSet<>();
            for (PickTaskDDTO pickTaskDDTO : ddtos) {
                if (StrUtil.isNotEmpty(pickTaskDDTO.getItemId())) {
                    itemIds.add(pickTaskDDTO.getItemId());
                }
            }
            vo.setItemIds(itemIds);
            vo.setPageNum(1);
            vo.setPageSize(9999);
            RestMessage<Page<ItemMstVO2>> restMessage = itemClient.pagebyRelated(vo);
            for (PickTaskDDTO pickTaskDDTO : list) {
                Map<String, Object> table = new HashMap<>();
                table.put("locatorCode", pickTaskDDTO.getLocatorCode());
                table.put("itemBar", "");
                if (null != restMessage.getData() && CollUtil.isNotEmpty(restMessage.getData().getList())) {
                    for (ItemMstVO2 itemMstVO2 : restMessage.getData().getList()) {
                        if (null != pickTaskDDTO.getItemId() && pickTaskDDTO.getItemId().equals(itemMstVO2.getItemId())) {
                            // 商品条码
                            table.put("itemBar", itemMstVO2.getBarCode());
                        }
                    }
                }
                table.put("itemName", pickTaskDDTO.getItemName());
                table.put("itemCode", pickTaskDDTO.getItemCode());
                table.put("pcs", pickTaskDDTO.getUomQty());
                table.put("odd", pickTaskDDTO.getOddPieceQty());
                table.put("qty", pickTaskDDTO.getQty());
                table.put("lotNo", pickTaskDDTO.getManufacturerLotNum());
                table.put("conversionRate", pickTaskDDTO.getConversionRate());
                tables.add(table);
                totQty = totQty.add(pickTaskDDTO.getQty());
                totPcs = totPcs.add(pickTaskDDTO.getUomQty());
                totOdd = totOdd.add(pickTaskDDTO.getOddPieceQty());
            }
            reportData.setTable(tables);
            head.put("pickOrderId", pickOrder.getPickOrderId());
            head.put("consignorCode", list.get(0).getConsignorName());
            head.put("pickerName", pickOrder.getOperatorName());
            head.put("billId", list.get(0).getBillNo());
            head.put("shipperCode", list.get(0).getShipperCode());
            head.put("shipperName", list.get(0).getShipperName());
            head.put("printCnt", null == pickOrder.getPrintCnt() ? 1 : pickOrder.getPrintCnt().intValue());
            head.put("itemCnt", itemIds.size());
            head.put("itemQty", totQty);
            head.put("itemPcs", totPcs);
            head.put("itemOdd", totOdd);
            reportData.setHead(head);
            printData.setData(Collections.singletonList(reportData));
            result.add(new PrintDataWithMark(printData, "3"));
        }
        return result;
    }

    /**
     * 补打整散合一列表
     *
     * @param printAgainVo
     * @return
     */
    @Override
    public Page<RePrintWholeBulkDto> listWholeBulkRepair(PrintAgainVo printAgainVo) {
        printAgainVo.setEnterpriseId(userTemplate.getUserDTO().getEnterpriseId());
        PageHelper.startPage(printAgainVo.getPageNum(), printAgainVo.getPageSize());
        List<RePrintWholeBulkDto> printDtos = pickTaskDMapper.listWholeBulkRepair(printAgainVo);
        Page<RePrintWholeBulkDto> result = PageUtils.getPage(printDtos);
        // 查询结果中货主无值， 查询货主信息并组装
        if (CollUtil.isNotEmpty(result.getList())) {
            Set<String> consignorIdSet = new HashSet<>();
            Set<String> shipper1 = new HashSet<>();
            Set<String> shipper2 = new HashSet<>();
            for (RePrintWholeBulkDto rePrintWholeBulkDto : result.getList()) {
                consignorIdSet.add(rePrintWholeBulkDto.getConsignorId());
                if (StrUtil.isNotEmpty(rePrintWholeBulkDto.getShipperId())) {
                    if (rePrintWholeBulkDto.getShipperType() == null || !rePrintWholeBulkDto.getShipperType().equals("1")) {
                        shipper2.add(rePrintWholeBulkDto.getShipperId());
                    } else {
                        shipper1.add(rePrintWholeBulkDto.getShipperId());
                    }
                }
            }
            List<BaseCargoOwnerMst> cargoOwnerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(consignorIdSet)) {
                RestMessage<Map<String, BaseCargoOwnerMst>> cargoMsg = chainResource.getCargoOwnerByIds(consignorIdSet);
                if (cargoMsg != null && CollUtil.isNotEmpty(cargoMsg.getData())) {
                    for (String s : cargoMsg.getData().keySet()) {
                        cargoOwnerMsts.add(cargoMsg.getData().get(s));
                    }
                }
            }
            List<BaseCustomerMst> customerMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper2)) {
                BaseCustomerMstRequestVO vo = new BaseCustomerMstRequestVO();
                vo.setEnterpriseid(printAgainVo.getEnterpriseId());
                vo.setIncludeSearchIds(shipper2);
                // 2 代表客户
                RestMessage<List<BaseCustomerMst>> restMessage = chainResource.findAll(vo);
                if (restMessage.isSuccess() && CollUtil.isNotEmpty(restMessage.getData())) {
                    customerMsts = restMessage.getData();
                }
            }
            List<BaseSupplierMst> supplierMsts = new ArrayList<>();
            if (CollUtil.isNotEmpty(shipper1)) {
                // 查询供应商
                RestMessage<Map<String, BaseSupplierMst>> supplierMst = chainResource.getSupplierMstByIds(shipper1);
                if (supplierMst.isSuccess() && CollUtil.isNotEmpty(supplierMst.getData())) {
                    for (String s : supplierMst.getData().keySet()) {
                        supplierMsts.add(supplierMst.getData().get(s));
                    }
                }
            }
            for (RePrintWholeBulkDto rePrintWholeBulkDto : result.getList()) {
                for (BaseCargoOwnerMst cargoOwnerMst : cargoOwnerMsts) {
                    if (cargoOwnerMst.getCargoOwnerId().equals(rePrintWholeBulkDto.getConsignorId())) {
                        rePrintWholeBulkDto.setConsignorName(cargoOwnerMst.getCargoOwnerName());
                        rePrintWholeBulkDto.setConsignorCode(cargoOwnerMst.getCargoOwnerCode());
                        break;
                    }
                }
                if (rePrintWholeBulkDto.getShipperType() == null || !rePrintWholeBulkDto.getShipperType().equals("1")) {
                    for (BaseCustomerMst customerMst : customerMsts) {
                        if (customerMst.getCustomerId().equals(rePrintWholeBulkDto.getShipperId())) {
                            rePrintWholeBulkDto.setShipperCode(customerMst.getCustomerCode());
                            rePrintWholeBulkDto.setShipperName(customerMst.getCustomerName());
                        }
                    }
                } else {
                    for (BaseSupplierMst supplierMst : supplierMsts) {
                        if (supplierMst.getSupplierId().equals(rePrintWholeBulkDto.getShipperId())) {
                            rePrintWholeBulkDto.setShipperCode(supplierMst.getSupplierCode());
                            rePrintWholeBulkDto.setShipperName(supplierMst.getSupplierName());
                        }
                    }
                }
            }
        }
        return result;
    }

    @Override
    public Page<RePrintWholeDto> billListForPrintAgain(PrintAgainVo printAgainVo) {
        PageHelper.startPage(printAgainVo.getPageNum(), printAgainVo.getPageSize());
        List<RePrintWholeDto> printDtos = outcomingRecordHMapper.queryPrintList(printAgainVo);
        return PageUtils.getPage(printDtos);
    }

    @Override
    public List<PrintDataWithMark> taskPrintAgain(TaskPrintAgainVo printAgainVo) {
        if (CollUtil.isEmpty(printAgainVo.getTaskIds())) {
            throw new BizException("请勾选要打印的任务");
        }
        if (CollUtil.isEmpty(printAgainVo.getTemplateTypes())) {
            throw new BizException("请勾选要打印的标签类型");
        }
        List<PrintDataWithMark> result = new ArrayList<>();
        for (String templateType : printAgainVo.getTemplateTypes()) {
            switch (templateType) {
                case "1":
                    result.addAll(this.movePrint(printAgainVo.getTaskIds(), printAgainVo.getWarehouseid()));
                    break;
                case "2":
                    result.addAll(this.pickPrint(printAgainVo.getTaskIds(), printAgainVo.getWarehouseid()));
                    break;
                case "3":
                    result.addAll(this.cxPrint(printAgainVo.getTaskIds(), printAgainVo.getWarehouseid()));
                    break;
            }
        }
        return result;
    }

    @Override
    public List<PrintDataWithMark> billPrintAgain(TaskPrintAgainVo printAgainVo) {
        List<PrintAgDateDto> printDataList = outcomingRecordHMapper.getAccompanyingListData(printAgainVo.getBillnos());
        // 个人清单打印时需要根据订单类型分组
        // 查询通用字典
        RestMessage<List<BaseCommonDict>> billTypeList = commonClient.getDictBasicListByCodes("special_bill_type", null);
        List<String> billTypes = billTypeList.getData().stream().map(BaseCommonDict::getDictCode).collect(Collectors.toList());
        List<PrintDataWithMark> result = new ArrayList<>();
        List<PrintAgDateDto> normalList = new ArrayList<>();
        List<PrintAgDateDto> specialList = new ArrayList<>();
        for (PrintAgDateDto outcomingRecordH : printDataList) {
            if (outcomingRecordH.getOutboundPrintCount() == null || outcomingRecordH.getOutboundPrintCount() > 0) {
                if (billTypes.contains(outcomingRecordH.getBilltype())) {
                    specialList.add(outcomingRecordH);
                } else {
                    normalList.add(outcomingRecordH);
                }
            } else {
                throw new BizException("选择的清单中有没有打印的清单！");
            }
        }
        if (normalList.size() > 0) {
            result.addAll(getOutboundPrintList(normalList, "NORMAL"));
        }
        if (specialList.size() > 0) {
            result.addAll(getOutboundPrintList(specialList, "SPECIAL"));
        }
        return result;
    }

    /**
     * 查询个人清单标签数据
     *
     * @param rsList   rsList
     * @param billType 普通订单、特殊订单
     * @return List<PrintData> list
     */
    public List<PrintDataWithMark> getOutboundPrintList(List<PrintAgDateDto> rsList, String billType) {
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        // 返回结果集
        List<ReportData> reportDataList = new ArrayList<>();
        // 打印的数据对象
        PrintData printData = new PrintData();
        printData.setPrintName("");
        for (PrintAgDateDto outcomingRecordH : rsList) {
            // 得到headMap数据
            Map<String, Object> head = this.queryPersonalInfo(outcomingRecordH);
            // 得到个人清单数据
            List<Map<String, Object>> table = this.queryItemInfoList(outcomingRecordH);
            ReportData reportData = new ReportData();
            reportData.setHead(head);
            reportData.setTable(table);
            reportDataList.add(reportData);
            // 更新打印次数
            outcomingRecordHMapper.updatePrintCount(outcomingRecordH.getBillid());
        }
        // 返回打印数据
        printData.setData(reportDataList);
        printData.setCount(reportDataList.size());
        printDataList.add(new PrintDataWithMark(printData, billType));
        return printDataList;
    }

    /**
     * 查询出库个人清单标签头数据
     *
     * @param outcomingRecordH outcomingRecordH
     * @return Map<String, Object> map
     */
    private Map<String, Object> queryPersonalInfo(PrintAgDateDto outcomingRecordH) {
        UserDTO userDTO = userTemplate.getUserDTO();
        String userName = userDTO.getUserBizModel().getEmployeeName();
        List<OutcomingRecordD> rsList = outcomingRecordH.getOutcomingRecordDList();
        Map<String, Object> map;
        if (rsList.size() > 0) {
            map = new HashMap<>();
            map.put("DJBH_YD", outcomingRecordH.getBillno());
            map.put("YEZHUCH", outcomingRecordH.getConsignorname());
            map.put("YPDL", ""); // 暂为空
            map.put("PSFXMC", outcomingRecordH.getShilineId()); // 送货方向
            map.put("YM", "1"); // 页数
            map.put("PSFX", outcomingRecordH.getShilineId()); // 送货方向编码
            map.put("DWMCH", outcomingRecordH.getShippername()); // 收货单位名称
            map.put("DANWBH", outcomingRecordH.getShippercode()); // 收货单位编号
            map.put("LXR", ""); // 开票单收货人
            map.put("LXRDH", ""); // 开票单联系方式
            map.put("KHBZ", ""); // 开票单客户备注
            map.put("RY_CZY", ""); // 开票单操作员
            map.put("RY_KPY", ""); // 开票单开票员
            map.put("RY_DYY", userName); // 打印员
            map.put("ZJS", outcomingRecordH.getTotPcs()); // 总件数
            map.put("SL_PXS", outcomingRecordH.getTotBoxNum()); // 总拼箱数
            return map;
        }
        return null;
    }

    /**
     * 查询出库个人清单标签数据
     *
     * @param outcomingRecordH outcomingRecordH
     * @return List<Map < String, Object>> list
     */
    private List<Map<String, Object>> queryItemInfoList(PrintAgDateDto outcomingRecordH) {
        List<OutcomingRecordD> rsList = outcomingRecordH.getOutcomingRecordDList();
        if (rsList.size() > 0) {
            List<Map<String, Object>> result = new ArrayList<>();
            Map<String, Object> map = null;
            for (OutcomingRecordD outcomingRecordD : rsList) {
                map = new HashMap<>();
                map.put("SPBH", outcomingRecordD.getItemcode()); // 商品编号
                map.put("TY", outcomingRecordD.getCategoryId()); // 商品规格
                map.put("DW", outcomingRecordD.getPackUnits()); // 商品包装单位
                map.put("LSJ", outcomingRecordD.getPrice()); // 零售价
                map.put("SL", outcomingRecordD.getAffirmedQty()); // 数量
                map.put("PH", outcomingRecordD.getLotNo()); // 批号
                map.put("YXQZ", outcomingRecordD.getValidUntil()); // 有效期至
                result.add(map);
            }
            return result;
        }
        return null;
    }

    private List<PrintDataWithMark> cxPrint(List<String> pickTaskIds, String warehouseId) {
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        // 创新物流打印
        // 查询属于创新物流的单
        // boxcnt 总箱数, ydbh 发运号(运单号), wdmch 网点名称, zcdfx 笼车号, picktime 拣货时间， shhr 收货人,printcnt 打印次数
        List<Map<String, Object>> maps = pickTaskDMapper.listCxPrintData(pickTaskIds, warehouseId);
        if (maps != null && maps.size() > 0) {
            for (Map<String, Object> map : maps) {
                if ((map.get("printcnt")) != null) {
                    map.put("printcnt", new BigDecimal("0"));
                }
                // 每箱一个标签
                for (int i = 0; i < ((BigDecimal) map.get("boxcnt")).intValue(); i++) {
                    String shipno = (String) map.get("ydbh");
                    Map<String, Object> head = new HashMap<>();
                    head.put("carcode", map.get("zcdfx"));
                    head.put("nodename", map.get("wdmch"));
                    head.put("lxr", map.get("shhr"));
                    head.put("shipno", map.get("ydbh"));
                    head.put("shipno1", shipno.substring(shipno.length() - 4) + "-" + i);
                    head.put("picktime", map.get("picktime"));
                    List<Map<String, Object>> table = new ArrayList<>();
                    ReportData reportData = new ReportData();
                    reportData.setHead(head);
                    reportData.setTable(table);
                    reportDatas.add(reportData);
                }
                // 更新打印次数
                waveBillDMapper.updateMapById(map.get("id"), MapUtils.put("cx_label_print", ((BigDecimal) map.get("printcnt")).intValue() + 1).getMap(), WaveBillDDO.class);
            }
        }
        printData.setData(reportDatas);
        printDataList.add(new PrintDataWithMark(printData, "CXLABEL"));
        return printDataList;
    }

    private List<PrintDataWithMark> pickPrint(List<String> pickTaskDIds, String warehouseId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        // 平库立库分开打印
        PrintData printDataPK = new PrintData();
        PrintData printDataLK = new PrintData();
        List<ReportData> reportDatasPK = new ArrayList<>();
        List<ReportData> reportDatasLk = new ArrayList<>();
        printDataPK.setPrintName("");
        List<Map<String, Object>> maps = pickTaskHMapper.getPickLabel(pickTaskDIds, warehouseId, userDTO.getEnterpriseId());
        if (maps != null && maps.size() > 0) {
            ItemMstQueryVO vo = new ItemMstQueryVO();
            Set<String> itemIds = new HashSet<>();
            for (Map<String, Object> map : maps) {
                if (null != map.get("itemId")) {
                    itemIds.add((String) map.get("itemId"));
                }
            }
            vo.setItemIds(itemIds);
            vo.setPageNum(1);
            vo.setPageSize(9999);
            RestMessage<Page<ItemMstVO2>> restMessage = itemClient.pagebyRelated(vo);
            if (!restMessage.isSuccess()) {
                throw new PrologException("调用查询商品接口出错！" + restMessage.getMessage());
            }
            for (Map<String, Object> map : maps) {
                Map<String, Object> head = new HashMap<>();
                // 客户名称
                head.put("khmch", map.get("DWMCH"));
                // 任务号
                head.put("taskId", map.get("BQ"));
                // 托盘号
                head.put("containerNo", map.get("container_code"));
                // 订单号
                head.put("billno", map.get("billno"));
                // 商品编码
                head.put("itemcode", map.get("itemcode"));
                // 商品条码
                head.put("barcode", map.get(""));
                if (null != restMessage.getData() && CollUtil.isNotEmpty(restMessage.getData().getList())) {
                    for (ItemMstVO2 itemMstVO2 : restMessage.getData().getList()) {
                        if (null != map.get("itemId") && map.get("itemId").equals(itemMstVO2.getItemId())) {
                            // 商品条码
                            String barCode = itemMstVO2.getBarCode();
                            head.put("barcode", barCode);
                        }
                    }
                }
                // 商品名称
                head.put("itemname", map.get("SPMCH"));
                // 商品规格
                head.put("specification", map.get("SHPGG"));
                // 待拣数量
                head.put("oddunqty", map.get("DD_JS"));
                // 生产厂家
                head.put("manufacturerName", map.get("SHENGCCJ"));
                // 包装数量
                head.put("caseConversionRate", map.get("JLGG"));
                // 批号
                head.put("manufacturerLotNum", map.get("PH"));
                // 收件人
                head.put("lxr", map.get("lxr"));
                // 联系方式
                head.put("lxfs", map.get("lxfs"));
                // 收件地址
                head.put("address", map.get("address"));

                ReportData reportData = new ReportData();
                reportData.setHead(head);
                if ("Device".equals(map.get("pickModel"))) {
                    // 货位
                    head.put("loccode", map.get("LOCATOR_CODE") + "楼" + map.get("LOCATOR_CODE") + "站台");
                    // 立库
                    reportDatasLk.add(reportData);
                } else {
                    // 货位
                    head.put("loccode", map.get("LOCATOR_CODE"));
                    // 平库
                    reportDatasPK.add(reportData);
                }
                pickTaskDMapper.updateMapById(map.get("BQ"), MapUtils.put("printCount", ((BigDecimal) map.get("PRINTCOUNT")).intValue() + 1).getMap(), PickTaskD.class);
                if (map.get("PRINTSTATUS") != null && map.get("PRINTSTATUS").equals("0"))
                    pickOrderMapper.updateMapById(map.get("PICKORDERID"), MapUtils.put("printStatus", "1").getMap(), PickOrder.class);
            }
        }
        printDataPK.setData(reportDatasPK);
        printDataLK.setData(reportDatasLk);
        printDataList.add(new PrintDataWithMark(printDataPK, "PKPICK"));
        printDataList.add(new PrintDataWithMark(printDataLK, "LKPICK"));
        return printDataList;
    }

    private List<PrintDataWithMark> movePrint(List<String> pickTaskDIds, String warehouseId) {
        UserDTO userDTO = userTemplate.getUserDTO();
        List<PrintDataWithMark> printDataList = new ArrayList<>();
        // 平库立库分开打印
        PrintData printData = new PrintData();
        List<ReportData> reportDatas = new ArrayList<>();
        printData.setPrintName("");
        List<Map<String, Object>> maps = pickTaskHMapper.getMoveLabel(pickTaskDIds, warehouseId, userDTO.getEnterpriseId());
        if (maps != null && maps.size() > 0) {
            for (Map<String, Object> map : maps) {
                Map<String, Object> head = new HashMap<>();
                // 任务号
                head.put("taskId", map.get("BQ"));
                // 商品编码
                head.put("itemcode", map.get("itemcode"));
                // 商品名称
                head.put("itemname", map.get("SPMCH"));
                // 商品规格
                head.put("specification", map.get("SHPGG"));
                // 生产厂家
                head.put("manufacturerName", map.get("SHENGCCJ"));
                // 包装数量
                head.put("caseConversionRate", map.get("JLGG"));
                // 批号
                head.put("manufacturerLotNum", map.get("PH"));
                BigDecimal zqty = (BigDecimal) map.get("Z_QTY");
                BigDecimal jlgg = (BigDecimal) map.get("JLGG");
                BigDecimal[] result = zqty.divideAndRemainder(jlgg);
                // 待拣数量
                head.put("pcs", result[0]);
                // 待拣数量
                head.put("lss", result[1]);
                // 上架货位
                head.put("destWarehouseLocatorNum", map.get("SJHW"));
                ReportData reportData = new ReportData();
                reportData.setHead(head);
                pickTaskDMapper.updateMapById(map.get("BQ"), MapUtils.put("printCount", ((BigDecimal) map.get("PRINTCOUNT")).intValue() + 1).getMap(), PickTaskD.class);
                if (map.get("PRINTSTATUS") != null && map.get("PRINTSTATUS").equals("0"))
                    pickOrderMapper.updateMapById(map.get("PICKORDERID"), MapUtils.put("printStatus", "1").getMap(), PickOrder.class);
            }
        }
        printData.setData(reportDatas);
        printDataList.add(new PrintDataWithMark(printData, "MOVEPICK"));
        return printDataList;
    }

    private void containerConfirm(InfTaskOutBackDTO dto) {
        RestMessage<?> msg = eisOutboundClient.confirmContainer(dto);
        if (null == msg || !msg.isSuccess()) {
            throw new BizException("WMS回传拣货确认至EIS失败！");
        }
    }

    @Override
    public Object execute(InterfaceBill dataObject) throws Exception {
        if (dataObject.getNo().equals("retry")) {
            throw new RetryException("retry test");
        }
        log.info("there is your interface proces");
        return null;
    }

    /**
     * @param dataObject
     * @return com.prolog.fx.inf.core.dto.LogInfo
     * @Description 转换日志信息
     * @param: dataObject
     * @Author chenyc
     * @Date 2021/8/9 18:25
     */
    @Override
    public SimpleLog toLog(InterfaceBill dataObject) {
        SimpleLog simpleLog = new SimpleLog();
        try {
            simpleLog.setData(JsonUtils.toString(dataObject));
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        simpleLog.setBussinessKey1(dataObject.getId());
        simpleLog.setBussinessKey2(dataObject.getNo());
        simpleLog.setBussinessKey3(dataObject.getCustomer());
        return simpleLog;
    }

    /**
     * @param simpleLog
     * @return D
     * @Description 转换数据对象
     * @param: logInfo
     * @Author chenyc
     * @Date 2021/8/9 18:25
     */
    @Override
    public InterfaceBill toDataObject(SimpleLog simpleLog) {
        if (simpleLog != null) {
            try {
                InterfaceBill bill = JsonUtils.parseJsonString(simpleLog.getData(), new TypeReference<InterfaceBill>() {
                });
                return bill;
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        return null;
    }

    /**
     *
     * @param pickTaskH
     * @param pickTaskDs
     * @param type 1零货 0整件
     * @param flag 1拣货确认 0索取
     * @return
     */
    @Transactional
    @FuncImpl(name = "生成barcode", func = OutBoundFunc.saveBarcode.class, description = "生成barcode")
    public boolean saveBarcode2(
            PickTaskH pickTaskH,
            List<PickTaskD> pickTaskDs,
            int type,
            String flag
    ) {
        OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(pickTaskH.getBillGroupId(), OmsDoBillHDO.class);
        if (omsDoBillHDO == null) {
            throw new BizException("查询oms订单汇总失败!");
        }
        Set<String> omsDoBillLineIds = pickTaskDs.stream().map(PickTaskD::getSrcLineId).collect(Collectors.toSet());
        List<OmsDoBillDDO> omsDoBillDDOS = omsDoBillDMapper.findByIds(OmsDoBillDDO.class, omsDoBillLineIds.toArray(), null);
        if(omsDoBillDDOS == null || omsDoBillDDOS.size() <= 0){
            throw new BizException("根据出库单明细id列表："+JSON.toJSONString(omsDoBillLineIds)+"查询出库单明细失败!");
        }
        if (type == 1) {
            BarcodeHDO barCodeHDO = new BarcodeHDO();
            if ("2".equals(omsDoBillHDO.getCarrierType())) {
                String barcode = BillUtils.getBarcode(redisTemplate);
                String maxBarcode = barcodeHMapper.getMaxBarcode();
                if (!StringUtils.isEmpty(maxBarcode) && Long.valueOf(maxBarcode) > Long.valueOf(barcode)) {
                    throw new BizException("标签号生成失败，不能重复生成!");
                }
                barCodeHDO.setBarcode(barcode);
                barCodeHDO.setBarcodeType("0");
            } else {
                barCodeHDO.setBarcode(null);
                barCodeHDO.setBarcodeType("1");
            }
            barCodeHDO.setId(UUIDUtils.generateWithoutSeperator());
            barCodeHDO.setType("0");
            barCodeHDO.setBillGroupId(pickTaskH.getBillGroupId());
            barCodeHDO.setStatus('0');
            barCodeHDO.setCheckStatus("0");
            barCodeHDO.setWarehouseId(pickTaskH.getWarehouseId());
            barCodeHDO.setBldgId(pickTaskH.getBldgId());
            barCodeHDO.setBldgName(pickTaskH.getBldgName());
            ModelUtils.generateBaseData(barCodeHDO, userTemplate::getUserDTO);
            if("1".equals(flag)){

                BigDecimal totalWeight = BigDecimal.ZERO;
                for (PickTaskD pickTaskD : pickTaskDs) {
                    OmsDoBillDDO omsDoBillDDO = omsDoBillDDOS.stream().filter(item -> item.getLineid().equals(pickTaskD.getSrcLineId())).findFirst().orElse(null);
                    if(omsDoBillDDO == null){
                        throw new BizException("匹配出库单明细失败!");
                    }
                    BigDecimal pcs = pickTaskD.getPickQty().divide(omsDoBillDDO.getPackTypeNum(),2,BigDecimal.ROUND_HALF_UP);
                    totalWeight =  totalWeight.add(omsDoBillDDO.getItemWeight().multiply(pcs));
                }
                barCodeHDO.setWeight(totalWeight.doubleValue());
            }
            barcodeHMapper.save(barCodeHDO);
            List<BarCodeDDO> barCodeDDOS = new ArrayList<>();
            for (PickTaskD pickTaskD : pickTaskDs) {
                BarCodeDDO barCodeDDO = new BarCodeDDO();
                barCodeDDO.setId(UUIDUtils.generateWithoutSeperator());
                ModelUtils.generateBaseData(barCodeDDO, userTemplate::getUserDTO);
                barCodeDDO.setBarcodeId(barCodeHDO.getId());
                barCodeDDO.setWmsPickTaskDId(pickTaskD.getPickTaskDId());
                barCodeDDO.setEnterpriseId(pickTaskH.getEnterpriseId());
                barCodeDDO.setWarehouseId(pickTaskH.getWarehouseId());
                Map<String, String> itemMap = pickTaskHMapper.getItemCode(pickTaskD.getPickTaskDId(), pickTaskH.getWarehouseId());
                if (itemMap != null && itemMap.containsKey("ITEM_ID")) {
                    barCodeDDO.setItemCode(itemMap.get("ITEM_CODE"));
                    barCodeDDO.setItemId(itemMap.get("ITEM_ID"));
                }
                barCodeDDO.setIsPiece(0);
                if("1".equals(flag)){
                    barCodeDDO.setQty(pickTaskD.getPickQty());
                }
                barCodeDDOS.add(barCodeDDO);
            }

            barcodeDMapper.saveBatch(barCodeDDOS);
        } else {
            for (PickTaskD pickTaskD : pickTaskDs) {
                WaveStorageDO waveStorageDO = waveStorageMapper.findById(pickTaskD.getWaveStorageId(), WaveStorageDO.class);
                WaveBillDDO waveBillDDO = billDMapper.findById(waveStorageDO.getBillDId(), WaveBillDDO.class);
                BigDecimal[] n;
                if("1".equals(flag)){
                    n = pickTaskD.getPickQty().divideAndRemainder(waveBillDDO.getCaseConversionRate());
                }else {
                    n = pickTaskD.getQty().divideAndRemainder(waveBillDDO.getCaseConversionRate());
                }
                int js = n[0].intValue();
                for (int i = 0; i < js; i++) {
                    BarcodeHDO barCodeHDO = new BarcodeHDO();
                    barCodeHDO.setId(UUIDUtils.generateWithoutSeperator());

                    if ("2".equals(omsDoBillHDO.getCarrierType())) {
                        String barcode = BillUtils.getBarcode(redisTemplate);
                        String maxBarcode = barcodeHMapper.getMaxBarcode();
                        if (!StringUtils.isEmpty(maxBarcode) && Long.valueOf(maxBarcode) > Long.valueOf(barcode)) {
                            throw new BizException("标签号生成失败，不能重复生成!");
                        }
                        barCodeHDO.setBarcode(barcode);
                        barCodeHDO.setBarcodeType("0");
                    } else {
                        barCodeHDO.setBarcode(null);
                        barCodeHDO.setBarcodeType("1");
                    }
                    barCodeHDO.setBillGroupId(pickTaskH.getBillGroupId());
                    barCodeHDO.setType("1"); // 整件拣选码
                    barCodeHDO.setStatus('0');
                    barCodeHDO.setWarehouseId(pickTaskH.getWarehouseId());
                    barCodeHDO.setBldgId(pickTaskH.getBldgId());
                    barCodeHDO.setBldgName(pickTaskH.getBldgName());
                    ModelUtils.generateBaseData(barCodeHDO, userTemplate::getUserDTO);
                    OmsDoBillDDO omsDoBillDDO = omsDoBillDDOS.stream().filter(item -> item.getLineid().equals(pickTaskD.getSrcLineId())).findFirst().orElse(null);
                    if(omsDoBillDDO == null){
                        throw new BizException("匹配出库单明细失败!");
                    }
                    barCodeHDO.setWeight(omsDoBillDDO.getItemWeight().doubleValue());
                    barcodeHMapper.save(barCodeHDO);

                    BarCodeDDO barCodeDDO = new BarCodeDDO();
                    barCodeDDO.setId(UUIDUtils.generateWithoutSeperator());
                    ModelUtils.generateBaseData(barCodeDDO, userTemplate::getUserDTO);
                    barCodeDDO.setBarcodeId(barCodeHDO.getId());
                    barCodeDDO.setWmsPickTaskDId(pickTaskD.getPickTaskDId());
                    barCodeDDO.setEnterpriseId(pickTaskH.getEnterpriseId());
                    barCodeDDO.setWarehouseId(pickTaskH.getWarehouseId());
                    Map<String, String> itemMap = pickTaskHMapper.getItemCode(pickTaskD.getPickTaskDId(), pickTaskH.getWarehouseId());
                    if (itemMap != null && itemMap.containsKey("ITEM_ID")) {
                        barCodeDDO.setItemCode(itemMap.get("ITEM_CODE"));
                        barCodeDDO.setItemId(itemMap.get("ITEM_ID"));
                    }
                    barCodeDDO.setIsPiece(0);
                    if("1".equals(flag)){
                        barCodeDDO.setQty(waveBillDDO.getCaseConversionRate());
                    }
                    barcodeDMapper.save(barCodeDDO);
                }
            }
        }
        return true;
    }


    @Override
    public void outboundTaskCallback(OutboundTaskCallbackVO vo) {
        List<OutboundTaskCallbackItemVO> tasks = vo.getSubList();
        cn.hutool.core.lang.Assert.notEmpty(tasks, "EIS回告任务不存在");

        String[] pickTaskDIds = tasks.stream().map(OutboundTaskCallbackItemVO::getTaskLineId).distinct().toArray(String[]::new);
        List<PickTaskD> pickTaskDList = pickTaskDMapper.findByIds(PickTaskD.class, pickTaskDIds, null);
        Assert.notEmpty(pickTaskDList, "获取拣货任务失败");

        String[] pickTaskHIds = pickTaskDList.stream().map(PickTaskD::getPickTaskId).distinct().toArray(String[]::new);
        List<PickTaskH> pickTaskHList = pickTaskHMapper.findByIds(PickTaskH.class, pickTaskHIds, null);
        Assert.notEmpty(pickTaskHList, "获取拣货汇总任务失败");

        String[] waveStorageIds = pickTaskDList.stream().map(PickTaskD::getWaveStorageId).distinct().toArray(String[]::new);
        List<WaveStorageDO> storageList = waveStorageMapper.findByIds(WaveStorageDO.class, waveStorageIds, null);
        Assert.notEmpty(storageList, "获取拣货预占失败");

        String[] waveBillDIds = storageList.stream().map(WaveStorageDO::getBillDId).distinct().toArray(String[]::new);
        List<WaveBillDDO> waveBillDList = waveBillDMapper.findByIds(WaveBillDDO.class, waveBillDIds, FieldSelector.newInstance().include("id", "caseConversionRate", "totalPcs"));
        Assert.notEmpty(waveBillDList, "获取波次任务失败");


        DateTime now = DateUtil.date();
        List<WaveStorageDO> pendingSaveStorageList = Lists.newArrayList();
        List<WaveStorageDO> pendingUpdateStorageList = Lists.newArrayList();
        List<PickTaskH> pendingSavePickTaskHList = Lists.newArrayList();
        List<PickTaskD> pendingSavePickTaskDList = Lists.newArrayList();
        List<PickTaskD> pendingUpdatePickTaskDList = Lists.newArrayList();

        FieldSelector pickTaskFields = FieldSelector.newInstance().include("qty", "gmtModified", "wholeNum","containerCode");
        FieldSelector storageFields = FieldSelector.newInstance().include("gmtModified", "modifier", "modifierName", "containerCode", "qty");

        for (OutboundTaskCallbackItemVO task : tasks) {

            PickTaskD pickTaskD = pickTaskDList.stream().filter(t -> t.getPickTaskDId().equals(task.getTaskLineId())).findFirst().orElse(null);
            cn.hutool.core.lang.Assert.notNull(pickTaskD, "根据TaskLineId:{}获取拣货任务明细失败", task.getTaskLineId());

            //初始和未索取的任务可以拆分
            if (!INITIALIZE.getCode().equals(pickTaskD.getFlowStatus()) && !GENERATE.getCode().equals(pickTaskD.getFlowStatus())) {
                throw new BizException(String.format("任务号【%s】非正常状态无法拆分", task.getTaskLineId()));
            }

            if (task.getQty() <= 0) {
                throw new BizException(String.format("任务号【%s】数量小于0无法拆分", task.getTaskLineId()));
            }

            //源出库任务预占
            WaveStorageDO sourceStorage = storageList.stream().filter(s -> s.getId().equals(pickTaskD.getWaveStorageId())).findFirst().orElse(null);
            cn.hutool.core.lang.Assert.notNull(sourceStorage, "获取任务ID【{}】库存预占失败", pickTaskD.getPickTaskDId());

            //计划拣选数量
            BigDecimal qty = pickTaskD.getQty();
            //EIS回告数量
            BigDecimal eisQty = new BigDecimal(task.getQty().toString());
            if (qty.compareTo(eisQty) < 0) {
                throw new BizException(String.format("任务号【%s】回告数量超过任务数量", task.getTaskLineId()));
            }
            //任务计划拣选数量大于回告数量满足拆分条件
            if (qty.compareTo(eisQty) > 0) {

                PickTaskH pickTaskH = pickTaskHList.stream().filter(t -> t.getPickTaskId().equals(pickTaskD.getPickTaskId())).findFirst().orElse(null);
                cn.hutool.core.lang.Assert.notNull(pickTaskH, "根据TaskLineId:{}获取拣货任务汇总失败", task.getTaskLineId());

                //源波次任务
                WaveBillDDO sourceWaveBillD = waveBillDList.stream().filter(w -> w.getId().equals(sourceStorage.getBillDId())).findFirst().orElse(null);
                cn.hutool.core.lang.Assert.notNull(sourceWaveBillD, "获取波次订单明细失败");

                log.info("___拆分前出库预占:{}", JSONObject.toJSONString(sourceStorage));
                sourceStorage.setQty(qty.subtract(eisQty));
                log.info("___拆分后出库预占:{}", JSONObject.toJSONString(sourceStorage));

                WaveStorageDO saveWaveStorageDO = generateStorageBySplit(vo, sourceStorage, eisQty, now);
                pendingSaveStorageList.add(saveWaveStorageDO);
                log.info("___拆分后新生成出库预占:{}", JSONObject.toJSONString(saveWaveStorageDO));

                updateSourceTask(pickTaskD, qty, eisQty, now, sourceWaveBillD);
                pendingUpdatePickTaskDList.add(pickTaskD);
                log.info("___拆分后拣货任务明细:{}", JSONObject.toJSONString(pickTaskD));

                PickTaskH saveTaskH = generateTaskHBySplit(pickTaskH, now);
                log.info("___拆分后新生成拣货汇总:{}", JSONObject.toJSONString(saveTaskH));
                pendingSavePickTaskHList.add(saveTaskH);

                PickTaskD saveTaskD = generateTaskDBySplit(pickTaskD, saveTaskH, eisQty, now, saveWaveStorageDO, sourceWaveBillD);
                log.info("___拆分后新生成拣货任务明细:{}", JSONObject.toJSONString(saveTaskD));
                pendingSavePickTaskDList.add(saveTaskD);
            } else {
                sourceStorage.setContainerCode(vo.getContainerNo());
                pickTaskD.setContainerCode(vo.getContainerNo());
                pickTaskD.setGmtModified(now);
                pendingUpdatePickTaskDList.add(pickTaskD);
            }
            sourceStorage.setGmtModified(now);
            sourceStorage.setModifier(EIS);
            sourceStorage.setModifierName(EIS);
            pendingUpdateStorageList.add(sourceStorage);
        }

        TransactionHelper.persistenceErrorThrow(() -> {
            if (CollUtil.isNotEmpty(pendingSaveStorageList)) {
                waveStorageMapper.saveBatch(pendingSaveStorageList);
            }

            if (CollUtil.isNotEmpty(pendingSavePickTaskDList)) {
                pickTaskDMapper.saveBatch(pendingSavePickTaskDList);
            }

            if (CollUtil.isNotEmpty(pendingSavePickTaskHList)) {
                pickTaskHMapper.saveBatch(pendingSavePickTaskHList);
            }

            if (CollUtil.isNotEmpty(pendingUpdateStorageList)) {
                pendingUpdateStorageList.forEach(s -> waveStorageMapper.updateFields(s, storageFields));
            }

            if (CollUtil.isNotEmpty(pendingUpdatePickTaskDList)) {
                pendingUpdatePickTaskDList.forEach(p -> pickTaskDMapper.updateFields(p, pickTaskFields));
            }
        });
    }

    private PickTaskH generateTaskHBySplit(PickTaskH pickTaskH, DateTime now) {
        PickTaskH saveTask = taskConvert.copyByPickTaskH(pickTaskH);
        saveTask.setPickTaskId(String.valueOf(SnowFlakeUtils.getId()));
        saveTask.setSplitSourceId(pickTaskH.getPickTaskId());
        saveTask.setGmtCreate(now);
        saveTask.setCreator(EIS);
        saveTask.setCreatorName(EIS);
        saveTask.setGmtModified(now);
        saveTask.setModifier(EIS);
        saveTask.setModifierName(EIS);
        return saveTask;
    }

    private WaveStorageDO generateStorageBySplit(OutboundTaskCallbackVO vo, WaveStorageDO sourceStorage, BigDecimal eisQty, DateTime now) {
        WaveStorageDO saveWaveStorageDO = taskConvert.copyByWaveStorageDO(sourceStorage);
        saveWaveStorageDO.setQty(eisQty);
        saveWaveStorageDO.setContainerCode(vo.getContainerNo());
        saveWaveStorageDO.setGmtModified(now);
        saveWaveStorageDO.setModifier(EIS);
        saveWaveStorageDO.setModifierName(EIS);
        saveWaveStorageDO.setId(String.valueOf(SnowFlakeUtils.getId()));
        return saveWaveStorageDO;
    }

    private void updateSourceTask(PickTaskD updateTask, BigDecimal qty, BigDecimal eisQty, DateTime now, WaveBillDDO sourceWaveBillD) {
        updateTask.setQty(qty.subtract(eisQty));
        updateTask.setGmtModified(now);
        String wholeNum = getWholeNum(updateTask.getQty(), sourceWaveBillD.getCaseConversionRate(), sourceWaveBillD.getTotalPcs());
        updateTask.setWholeNum(wholeNum);
    }

    private PickTaskD generateTaskDBySplit(PickTaskD updateTask, PickTaskH pickTaskH, BigDecimal eisQty, DateTime now, WaveStorageDO saveWaveStorageDO, WaveBillDDO sourceWaveBillD) {
        String wholeNum;
        PickTaskD saveTask = taskConvert.copyByPickTaskD(updateTask);
        saveTask.setPickTaskDId(String.valueOf(SnowFlakeUtils.getId()));
        saveTask.setPickTaskId(pickTaskH.getPickTaskId());
        saveTask.setQty(eisQty);
        saveTask.setGmtCreate(now);
        saveTask.setCreator(EIS);
        saveTask.setCreatorName(EIS);
        saveTask.setGmtModified(now);
        saveTask.setModifier(EIS);
        saveTask.setModifierName(EIS);
        saveTask.setWaveStorageId(saveWaveStorageDO.getId());
        wholeNum = getWholeNum(saveTask.getQty(), sourceWaveBillD.getCaseConversionRate(), sourceWaveBillD.getTotalPcs());
        saveTask.setWholeNum(wholeNum);
        saveTask.setSplitSourceId(updateTask.getPickTaskDId());
        saveTask.setContainerCode(saveWaveStorageDO.getContainerCode());
        return saveTask;
    }

    private String getWholeNum(BigDecimal qty, BigDecimal caseConversionRate, Integer totalPcs) {
        BigDecimal pcs = qty.divideAndRemainder(caseConversionRate)[0];
        return String.format("%s/%s", pcs.intValue(), totalPcs);
    }

    /**
     * @param list
     * @Result 0：缺货冲红,1：重新推任务
     * 0:EIS缺货短拣，并供包时，标记为异常订单；线下处理异常；
     * <p>
     * 1:WMS短拣部分重新追加明细，追加明细订单号为原订单号，明细行增加短拣数量；后续补发任务与原任务行数量挂靠，后续继续拣选；
     * 拆零拣选完成后，票据可执行，不需要等待零发整拣选任务；
     * 拆零短拣与零发整短拣数量需记录短拣数量；
     */
    @Override
    @TxTransaction(isStart = true)
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> completeTask(List<CompleteTaskVO> list) {
        log.info("eis作业完成回告入参：{}",JSON.toJSONString(list));
        Map<String,Object> map = new HashMap<>();
        List<CompleteTaskVO> lfzList = list.stream().filter(item -> item.getIsLfz() != null && item.getIsLfz() == 1).collect(Collectors.toList());

        String[] pickTaskDIds = list.stream().map(CompleteTaskVO::getTaskLineId).distinct().toArray(String[]::new);
        cn.hutool.core.lang.Assert.notEmpty(pickTaskDIds, "EIS回告任务明细ID数据出错");

        List<PickTaskD> tasks = pickTaskDMapper.findByIds(PickTaskD.class, pickTaskDIds, null);
        cn.hutool.core.lang.Assert.notEmpty(tasks, "获取拣货任务失败");

        //获取本次拣货任务对应汇总下的所有拣货任务
        String[] pickTaskIds = tasks.stream().map(PickTaskD::getPickTaskId).distinct().toArray(String[]::new);
        List<PickTaskD> wholeTasks = pickTaskDMapper.getPickTaskDListByPickTaskIds(pickTaskIds);
        cn.hutool.core.lang.Assert.notEmpty(wholeTasks, "获取所有拣选任务失败");

        //封装待更新参数
        List<PickTaskD> pendingTasks = this.warpPendingTasks(list, tasks);

        //获取出库预占
        String[] storageIds = pendingTasks.stream().map(PickTaskD::getWaveStorageId).distinct().toArray(String[]::new);
        List<WaveStorageDO> storages = waveStorageMapper.findByIds(WaveStorageDO.class, storageIds, FieldSelector.newInstance().include("id", "batchNum", "warehouseId", "bldgId"));
        cn.hutool.core.lang.Assert.notEmpty(storages, "获取出库预占失败");

        FieldSelector fs1 = FieldSelector.newInstance().include("pickQty", "pickerId", "pickerNo", "pickerName", "flowStatus", "containerCode", "pickTime","saleRedQty");
        pendingTasks.forEach(pt -> pickTaskDMapper.updateFields(pt, fs1));

        //拣货汇总下的任务是否全部完成,如果是就更新汇总状态
        String[] taskHIds = isAllDone(pendingTasks, wholeTasks);
        boolean taskHdrIsDone = ArrayUtil.isNotEmpty(taskHIds) ? this.updatePickTaskHByIds(taskHIds) : false;
        log.info("taskHIds:{},isDone:{}", taskHIds, taskHdrIsDone);

        //短拣逻辑
        List<PickTaskD> lackTasks = pendingTasks.stream().filter(t -> t.getSaleRedQty().doubleValue() > 0).collect(Collectors.toList());

        //EIS返回参数:0：缺货冲红,1：重新推任务
        Map<String,Object> flg = CollUtil.isNotEmpty(lackTasks) ? this.getFlgByLackTasks(storages, lackTasks) : null;
        log.info("getFlgByLackTasks:{},flg:{}", JSONObject.toJSONString(lackTasks), flg);

        //扣减库存
        List<InvStockPartCheckOut> costStocks = this.packCostStockParams(pendingTasks, storages);
        log.info("completeTask costStocks:{}", JSONObject.toJSONString(costStocks));

        costStocks.forEach(cs -> {
            log.info("completeTask outPartStockCheck:{}", JSONObject.toJSONString(cs));
            RestMessage msg = invClient.outPartStockCheck(cs);
            cn.hutool.core.lang.Assert.isTrue(msg.isSuccess(), msg.getMessage());
        });

        //判断是否是零发整
        if(lfzList != null && lfzList.size() > 0){
            CompleteTaskVO taskVO = lfzList.get(0);
            PickTaskD pickTaskD = tasks.stream().filter(item -> item.getPickTaskDId().equals(taskVO.getTaskLineId())).findFirst().orElse(null);
            if(pickTaskD == null){
                throw new BizException("任务明细ID："+pickTaskD.getPickTaskDId()+"不存在!");
            }
            OmsDoBillDDO omsDoBillDDO = omsDoBillDMapper.findById(pickTaskD.getSrcLineId(), OmsDoBillDDO.class);
            if(omsDoBillDDO == null){
                throw new BizException("根据订单明细id："+pickTaskD.getSrcLineId()+"查询失败!");
            }
            BigDecimal packTypeNum = omsDoBillDDO.getPackTypeNum();
            BigDecimal pickQty = new BigDecimal(taskVO.getInventoryQty());
            int pcs = pickQty.divide(packTypeNum).intValue();
            PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
            if(pickTaskH == null){
                throw new BizException("任务id："+pickTaskD.getPickTaskId()+"查询失败!");
            }
            OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(pickTaskD.getSrcId(), OmsDoBillHDO.class);
            if(omsDoBillHDO == null){
                throw new BizException("根据订单id："+pickTaskD.getSrcId()+"查询失败!");
            }
            //如果订单明细全部零发整
            BigDecimal qty = pickQty.add(taskVO.getLackQty() == null ? BigDecimal.ZERO : new BigDecimal(taskVO.getLackQty()));
            if(qty.compareTo(pickTaskD.getQty()) == 0){
                //删除原有的barcode
                List<BarCodeDDO> barCodeDDOS = barcodeDMapper.findByMap(MapUtils.put("wmsPickTaskDId", pickTaskD.getPickTaskDId()).getMap(), BarCodeDDO.class);
                barcodeDMapper.deleteByMap(MapUtils.put("wmsPickTaskDId", pickTaskD.getPickTaskDId()).getMap(), BarCodeDDO.class);
                if(barCodeDDOS != null && barCodeDDOS.size() > 0){
                    Set<String> barcodeIds = barCodeDDOS.stream().map(BarCodeDDO::getBarcodeId).collect(Collectors.toSet());
                    //判断barcodeH是否还有barcoded，没有则删除
                    for (String barcodeId : barcodeIds) {
                        long count = barcodeDMapper.findCountByMap(MapUtils.put("barcodeId", barcodeId).getMap(), BarCodeDDO.class);
                        if(count <= 0){
                            barcodeHMapper.deleteById(barcodeId,BarcodeHDO.class);
                        }
                    }
                }
            }

            //重新生成整件barcode
            List<String> lfzBarcodes = this.lfzSavebarcodes(pickTaskH, omsDoBillHDO, pickTaskD, omsDoBillDDO, pcs);
            map.put("barcodes",lfzBarcodes);
            map.put("employeeId",taskVO.getEmployeeId());
            map.put("billNo",omsDoBillHDO.getBillno());
            map.put("isLfz","1");
        }else {
            map.put("isLfz","0");
        }

        map.put("taskHIds",String.join(",",tasks.stream().map(PickTaskD :: getPickTaskId).distinct().collect(Collectors.toList())));
//        //当订单所有零货任务拣完后打印发票和清单
//        if(taskHIds != null && taskHIds.length > 0){
//            map.put("taskHIds",String.join(",",taskHIds));
//        }
        List<CompleteTaskVO> completeTaskVOS = new ArrayList<>();
        if(flg != null && flg.entrySet() != null && flg.entrySet().size() > 0){
            for (Map.Entry<String, Object> entry : flg.entrySet()) {
                String key = entry.getKey();
                if(StringUtils.isBlank(key)){
                    continue;
                }
                String value = (String) entry.getValue();
                CompleteTaskVO completeTaskVO = list.stream().filter(item -> key.equals(item.getTaskLineId())).findFirst().orElse(null);
                if(completeTaskVO != null ){
                    completeTaskVO.setFlg(value);
                    completeTaskVOS.add(completeTaskVO);
                }
            }
        }
        map.put("flg",completeTaskVOS.size() > 0 ? completeTaskVOS : null );

        //插入补货临时表
        ServletRequestAttributes reqa = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
        new Thread(()-> {
            RequestContextHolder.setRequestAttributes(reqa, false);
            ServletRequestAttributes servletRequestAttributes =
                    (ServletRequestAttributes)RequestContextHolder.currentRequestAttributes();
            String userkey = servletRequestAttributes.getRequest().getHeader("UserKey");

            if (!HystrixRequestContext.isCurrentThreadInitialized()) {
                HystrixRequestContext.initializeContext();
            }
            HystrixVarUtil.setUserKey(userkey);
            try {
                for (PickTaskD pickTaskD : tasks) {
                    PickTaskH pickTaskH = pickTaskHMapper.findById(pickTaskD.getPickTaskId(), PickTaskH.class);
                    //判断是否为拣货任务，且商品是A品
                    if(pickTaskD.getPickTaskType() == 1 && pickTaskH.getType() == 0){
                        RestMessage<List<WaveItemInfoVO>> clientListByIds = itemClient.getWaveItemInfo(CollUtil.toList(pickTaskD.getItemId()));
                        if(clientListByIds != null && clientListByIds.isSuccess() && clientListByIds.getData() != null && clientListByIds.getData().size() > 0){
                            List<WaveItemInfoVO> itemInfoVOS = clientListByIds.getData();
                            WaveItemInfoVO waveItemInfoVO = itemInfoVOS.get(0);
                            if("A".equals(waveItemInfoVO.getAbcType())){
                                //校验是否已经存在未补货的数据
                                long count = wmsRepPreMapper.findCountByMap(MapUtils.put("itemId", pickTaskD.getItemId()).put("status","0").getMap(), WmsRepPre.class);
                                if(count > 0){
                                    return;
                                }
                                WmsRepPre wmsRepPre = new WmsRepPre();
                                wmsRepPre.setId(UUIDUtils.generateWithoutSeperator());
                                wmsRepPre.setItemId(pickTaskD.getItemId());
                                wmsRepPre.setWarehouseId(pickTaskD.getWarehouseId());
                                wmsRepPre.setEnterpriseId(pickTaskD.getEnterpriseId());
                                wmsRepPre.setStatus("0");
                                wmsRepPre.setCreator(pickTaskD.getCreator());
                                wmsRepPre.setGmtCreate(new Date());
                                wmsRepPre.setModifier(pickTaskD.getModifier());
                                wmsRepPre.setGmtModified(new Date());
                                wmsRepPreMapper.save(wmsRepPre);
                            }
                        }
                    }
                }
            }catch (Exception e) {
                log.error("保存到补货临时表：{}", e.getMessage());
            }finally {
                RequestContextHolder.resetRequestAttributes();
            }
        }).start();
        return map;
    }

    @Transactional
    @Override
    public void printDetailAndFp(String taskHIds) {
        //根据通用参照打印节点判断是否打印出库清单和发票（1.拣货第一个任务确认后触发打印 2.整单拣货完成触发打印 3.复核完成打印）
        int printNode = getDetailAndInvoicePrintCode();

        String[] taskhIdArr = taskHIds.split(",");
        List<PickTaskH> pickTaskHS = pickTaskHMapper.findByIds(PickTaskH.class, taskhIdArr,FieldSelector.newInstance().include("billGroupId"));
        if(pickTaskHS == null || pickTaskHS.size() <= 0){
            throw new BizException("根据拣货任务Id："+taskHIds+"查询拣货任务失败!");
        }
        if(printNode == 3){
            return;
        }

        if(printNode == 1){
            Set<String> billIds = pickTaskHS.stream().map(PickTaskH::getBillGroupId).collect(Collectors.toSet());
            for (String billId : billIds) {
                boolean isPirnt = false;
                List<String> printCodes = CollUtil.toList("OutBillQnCg","OutBillQn-ZH","OutBillYM-YP","OutBillYM-QX","OutBillYM-SP","OutBillQn-NB","invoice-pdf");
                //判断订单是否打印过出库清单
                Criteria cr = Criteria.forClass(PrintLog.class);
                Restriction rh1 = Restrictions.eq("billno", billId);
                Restriction rh2 = Restrictions.in("printCode", printCodes.toArray());
                cr.setRestriction(Restrictions.and(rh1, rh2));
                List<PrintLog> printLogs = printLogMapper.findByCriteria(cr);
                if(printLogs == null || printLogs.size() <= 0){
                    isPirnt = true;
                }
                long count = printLogs.stream().filter(item -> "invoice-pdf".equals(item.getPrintCode())).count();
                long count2 = printLogs.stream().filter(item -> !"invoice-pdf".equals(item.getPrintCode())).count();
                if(count == 0 || count2 == 0){
                    isPirnt = true;
                }

                if(isPirnt){
                    OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(billId, OmsDoBillHDO.class);
                    omsDoBillHDO.setAttrNum4(new BigDecimal(count2));
                    try {
                        TimeInterval timer = DateUtil.timer();
                        print(omsDoBillHDO, null);
                        log.info("print detail and invoice done,cost:{}", timer.intervalRestart());
                    }catch (Exception e){
                        e.printStackTrace();
                        log.info("eis作业完成回告，打印出库清单发票失败：{}",e.getMessage());
                    }
                }
            }

        }else {
            try {
                Set<String> billIds = pickTaskHS.stream().map(PickTaskH::getBillGroupId).collect(Collectors.toSet());
                for (String billId : billIds) {
                    Criteria crth = Criteria.forClass(PickTaskH.class);
                    Restriction rh1 = Restrictions.eq("billGroupId", billId);
                    Restriction rh2 = Restrictions.lt("status", 2);
                    Restriction rh3 = Restrictions.notIn("pickTaskId", taskhIdArr);
                    Restriction rh4 = Restrictions.eq("pickTaskType", 1);
                    crth.setRestriction(Restrictions.and(rh1, rh2,rh3,rh4));
                    long count = pickTaskHMapper.findCountByCriteria(crth);
                    if(count <= 0){
                        OmsDoBillHDO omsDoBillHDO = omsDoBillHMapper.findById(billId, OmsDoBillHDO.class);
                        if(omsDoBillHDO == null){
                            throw new BizException("根据订单id:"+billId+"查询订单失败!");
                        }
                        TimeInterval timer = DateUtil.timer();
                        print(omsDoBillHDO, null);
                        log.info("outboundCheckResultCallback print done,cost:{}", timer.intervalRestart());
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                log.error("打印操作失败:{}", e.getMessage());
            }
        }

    }

    @Override
    public void changeTaskQty(List<MarkTaskItemVO> list) {
        log.info("changeTaskQty入参：{}",JSON.toJSONString(list));
        for (MarkTaskItemVO itemVO : list) {
            Criteria crt = Criteria.forClass(PickTaskD.class);
            Restriction r1 = Restrictions.eq("billDId", itemVO.getTaskLineId());
            crt.setRestriction(Restrictions.and(r1));
            pickTaskDMapper.updateMapByCriteria(MapUtils.put("qty", itemVO.getQty()).put("containerCode",itemVO.getContainerNo()).getMap(), crt);
        }
    }

    private boolean updatePickTaskHByIds(String[] taskHIds) {
        DateTime now = DateUtil.date();
        FieldSelector fs2 = FieldSelector.newInstance().include("pickTaskId", "status", "modifier", "gmtModified", "modifierName");
        List<PickTaskH> taskHList = pickTaskHMapper.findByIds(PickTaskH.class, taskHIds, fs2);
        cn.hutool.core.lang.Assert.notEmpty(taskHList, "获取拣货任务拣货失败");
        taskHList.forEach(th -> {
            th.setStatus(PickTaskHStatus.WAIT_TO_INNER_REVIEW_CLAIM.getCode());
            th.setModifier(EIS);
            th.setGmtModified(now);
            th.setModifierName(EIS);
            pickTaskHMapper.updateFields(th, fs2);
        });
        return true;
    }

    public Map<String,Object> getFlgByLackTasks(List<WaveStorageDO> storages, List<PickTaskD> lackTasks) {
        Date now = DateUtil.date();
        WaveStorageDO ws = storages.get(0);
        String warehouseId = ws.getWarehouseId();
        String bldgId = ws.getBldgId();
        // 转移到盘点库
        String locatorId = RestMsgHelper.getData(warehouseResource.getLocatorIdByCategory("PDK", warehouseId));
        cn.hutool.core.lang.Assert.notEmpty(locatorId, "获取盘点库货位ID失败");

        //冲红参数封装
        List<UpdateStockVO> usvs = Lists.newArrayList();
        List<SaleRedRecord> srrs = Lists.newArrayList();
        lackTasks.forEach(pt -> {
            UpdateStockVO usv = warpUpdateStockVO(pt);
            usvs.add(usv);

            SaleRedRecord srr = warpSaleRedRecord(pt, bldgId, now);
            srrs.add(srr);
        });

        saleRedRecordMapper.saveBatch(srrs);

        return this.updateStock2(usvs, warehouseId, locatorId, "0");

    }

    private UpdateStockVO warpUpdateStockVO(PickTaskD pt) {
        UpdateStockVO usv = new UpdateStockVO();
        usv.setBillId(pt.getBillId());
        usv.setBillDId(pt.getBillDId());
        usv.setRedQty(pt.getSaleRedQty());
        usv.setPickTaskDId(pt.getPickTaskDId());
        usv.setBatchId(pt.getBatchId());
        usv.setQty(pt.getQty());
        usv.setPickName(pt.getPickerName());
        return usv;
    }

    private SaleRedRecord warpSaleRedRecord(PickTaskD pt, String bldgId, Date now) {
        SaleRedRecord srr = new SaleRedRecord();
        srr.setQty(pt.getSaleRedQty());
        srr.setPickTaskDId(pt.getPickTaskDId());
        srr.setType(0);
        srr.setReason("拣货数量不足");
        srr.setBillDId(pt.getBillDId());
        srr.setBillId(pt.getBillId());
        srr.setItemId(pt.getItemId());
        srr.setSrcCode(pt.getSrcCode());
        srr.setStatus(0);
        srr.setPickerId(pt.getPickerId());
        srr.setPickerName(pt.getPickerName());
        srr.setPickerNo(pt.getPickerNo());
        srr.setBldgId(bldgId);
        srr.setWarehouseId(pt.getWarehouseId());
        srr.setEnterpriseId(pt.getEnterpriseId());
        srr.setCreator(pt.getPickerId());
        srr.setCreatorName(pt.getPickerName());
        srr.setGmtCreate(now);
        srr.setSrcId(pt.getSrcId());
        srr.setSrcLineId(pt.getSrcLineId());
        return srr;
    }

    public List<PickTaskD> warpPendingTasks(List<CompleteTaskVO> list, List<PickTaskD> tasks) {

        PickTaskD pickedTaskD = tasks.stream().filter(t -> Integer.parseInt(t.getFlowStatus()) >= Integer.parseInt(TASK_CONFIRMED.getCode())).findFirst().orElse(null);
        cn.hutool.core.lang.Assert.isNull(pickedTaskD, "任务【{}】不可重复拣货", pickedTaskD != null ? pickedTaskD.getPickTaskDId() : "");

        String[] employeeNos = list.stream().map(CompleteTaskVO::getEmployeeId).distinct().toArray(String[]::new);
        PickTaskD taskD = tasks.get(0);
        List<Employee> employees = getEmployees(employeeNos, taskD.getWarehouseId(), taskD.getEnterpriseId());
        log.info("EIS作业完成回告，查询员工信息:{}",JSON.toJSONString(employees));

        Map<String, List<CompleteTaskVO>> maps = list.stream().collect(Collectors.groupingBy(CompleteTaskVO::getTaskLineId));

        List<PickTaskD> pendingTasks = Lists.newArrayList();
        Date now = DateUtil.date();
        for (Map.Entry<String, List<CompleteTaskVO>> entry : maps.entrySet()) {
            List<CompleteTaskVO> completeTasks = entry.getValue();
            String taskLineId = entry.getKey();

            PickTaskD pickTask = tasks.stream().filter(t -> t.getPickTaskDId().equals(taskLineId)).findFirst().get();
            cn.hutool.core.lang.Assert.notNull(pickTask, "任务行号【{}】暂无任务", taskLineId);

            //WMS原拣货数量
            BigDecimal pickQty = pickTask.getPickQty() == null ? BigDecimal.ZERO : pickTask.getPickQty();
            //EIS实拣数量
            BigDecimal inventoryQty = completeTasks.stream().map(t -> new BigDecimal(t.getInventoryQty().toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
            //EIS短拣数量
            BigDecimal lackQty = completeTasks.stream().map(t -> new BigDecimal(t.getLackQty().toString())).reduce(BigDecimal.ZERO, BigDecimal::add);
            //EIS总数量，需要根据这个判断是否拣完
            BigDecimal eisQty = inventoryQty.add(pickQty).add(lackQty);

            int i = eisQty.compareTo(pickTask.getQty());
            if (i > 0) {
                throw new BizException(String.format("任务行号【%s】超出实际拣货总数量【%s】", taskLineId, pickTask.getQty()));
            }
            pickTask.setFlowStatus(PickTaskDFLowStatus.TASK_CLAIMED.getCode());
            if (i == 0) {
                pickTask.setFlowStatus(PickTaskDFLowStatus.TASK_CONFIRMED.getCode());
            }
            CompleteTaskVO vo = completeTasks.get(0);
            //实际扣库存数量
            pickTask.setChecker2Qty(inventoryQty.add(lackQty));
            pickTask.setPickQty(inventoryQty.add(pickQty));
            pickTask.setSaleRedQty(lackQty);
            pickTask.setPickerNo(vo.getEmployeeId());
            employees.stream().filter(ep -> ep.getJobnumber().equals(vo.getEmployeeId())).findFirst().ifPresent(ep -> {
                pickTask.setPickerId(ep.getUserId());
                pickTask.setPickerName(ep.getLocname());
                pickTask.setPickerNo(ep.getJobnumber());
            });
            pickTask.setPickTime(now);
            pickTask.setContainerCode(vo.getContainerNo());
            pendingTasks.add(pickTask);
        }
        return pendingTasks;
    }

    /**
     * EIS整单复核
     */
    @Override
    public void outboundCheckResultCallback(OutboundCheckResultCallbackVO vo) {

        TimeInterval timer = DateUtil.timer();

        List<OutboundCheckResultCallbackItemVO> subList = vo.getSubList();
        cn.hutool.core.lang.Assert.notEmpty(subList, "获取subList失败");

        String[] taskLineIds = subList.stream().map(OutboundCheckResultCallbackItemVO::getTaskLineId).distinct().toArray(String[]::new);
        List<PickTaskD> ptDtls = pickTaskDMapper.findByIds(PickTaskD.class, taskLineIds, null);
        cn.hutool.core.lang.Assert.notEmpty(ptDtls, "获取拣货任务失败");

        checkStatusByPickTasks(ptDtls);

        String[] pickTaskIds = ptDtls.stream().map(PickTaskD::getPickTaskId).distinct().toArray(String[]::new);

        Criteria pth = Criteria.forClass(PickTaskH.class);
        FieldSelector pthfs = FieldSelector.newInstance().include("bldgId", "bldgName", "modifier", "modifierName", "gmtModified", "status", "pickTaskId");
        pth.restrictionBuilder().in("pickTaskId", pickTaskIds);
        pth.buildRestriction();
        List<PickTaskH> ptHdrs = pickTaskHMapper.findFieldsByCriteria(pthfs, pth);
        cn.hutool.core.lang.Assert.notEmpty(ptHdrs, "获取拣货汇总失败");

        Employee employee = RestMsgHelper.getData(powerResource.getByNum(vo.getEmployeeId(), vo.getWarehouseId(), vo.getEnterpriseId()));
        cn.hutool.core.lang.Assert.notNull(employee, "根据工号【{}】获取员工信息失败", vo.getEmployeeId());

        List<OmsDoBillHDO> doBills = omsDoBillHMapper.findByMap(MapUtils.put("billno", vo.getBillNo()).put("branchid", vo.getWarehouseId()).getMap(), OmsDoBillHDO.class);
        cn.hutool.core.lang.Assert.notEmpty(doBills, "根据订单号【{}】获取出库单汇总信息失败", vo.getBillNo());

        OmsDoBillHDO omsDoBillHDO = doBills.get(0);

        FieldSelector bdfs = FieldSelector.newInstance().include("id", "barcodeId", "modifier", "modifierName", "gmtModified", "checkStatus", "printCnt");
        Criteria crt2 = Criteria.forClass(BarCodeDDO.class);
        crt2.restrictionBuilder().in("wmsPickTaskDId", taskLineIds);
        crt2.buildRestriction();
        List<BarCodeDDO> bDtls = barcodeDMapper.findFieldsByCriteria(bdfs, crt2);
        cn.hutool.core.lang.Assert.notEmpty(bDtls, "获取条码明细信息失败");

        String[] barcodeIds = bDtls.stream().map(BarCodeDDO::getBarcodeId).distinct().toArray(String[]::new);

        FieldSelector bhfs = FieldSelector.newInstance().include("id", "checkStatus", "checkTime", "modifier", "modifierName", "gmtModified", "checkerId", "checkerNo", "checkerName", "printCount");
        List<BarcodeHDO> bHdrs = barcodeHMapper.findByIds(BarcodeHDO.class, barcodeIds, bhfs);
        cn.hutool.core.lang.Assert.notEmpty(bHdrs, "获取条码汇总信息失败");

        log.info("outboundCheckResultCallback query done,cost:{}", timer.intervalRestart());
        DateTime now = DateUtil.date();

        TransactionHelper.persistenceErrorThrow(() -> {

            bHdrs.forEach(h -> {
                h.setCheckStatus("4");
                h.setCheckTime(now);
                h.setModifier(employee.getUserId());
                h.setModifierName(employee.getUsername());
                h.setGmtModified(now);
                h.setCheckerId(employee.getUserId());
                h.setCheckerNo(employee.getJobnumber());
                h.setCheckerName(employee.getLocname());
                h.setPrintCount(1);
                barcodeHMapper.updateFields(h, bhfs);
            });

            bDtls.forEach(d -> {
                d.setModifier(employee.getUserId());
                d.setModifierName(employee.getUsername());
                d.setGmtModified(now);
                d.setCheckStatus("4");
                d.setPrintCnt(1);
                PickTaskD pickTaskD = ptDtls.stream().filter(item -> item.getPickTaskDId().equals(d.getWmsPickTaskDId())).findFirst().orElse(null);
                if(pickTaskD != null){
                    d.setQty(pickTaskD.getPickQty());
                }
                barcodeDMapper.updateFields(d, bdfs);
            });

//            FieldSelector fs2 = FieldSelector.newInstance().include("flowStatus", "pickTaskId");
//            ptDtls.forEach(d -> {
//                d.setFlowStatus(OUT_REVIEW_CONFIRMED.getCode());
//                pickTaskDMapper.updateFields(d, fs2);
//            });
//
//            ptHdrs.forEach(h -> {
//                h.setModifier(employee.getUserId());
//                h.setModifierName(employee.getUsername());
//                h.setGmtModified(now);
//                h.setStatus(PickTaskHStatus.FINISHED.getCode());
//                pickTaskHMapper.updateFields(h, pthfs);
//            });
        });
        log.info("outboundCheckResultCallback do transaction done,cost:{}", timer.intervalRestart());

        getUserDtoKeyAndSetCache(employee.getUsername());
        try {
            int prinNode = getDetailAndInvoicePrintCode();
            if(prinNode == 3){
                print(omsDoBillHDO, employee);
            }
            log.info("outboundCheckResultCallback print done,cost:{}", timer.intervalRestart());
        } catch (Exception e) {
            log.error("打印操作失败", e);
        }

        try {
            saveSuperVisionCode(vo, omsDoBillHDO, employee, ptDtls);
            log.info("outboundCheckResultCallback saveSuperVisionCode done,cost:{}", timer.intervalRestart());
        } catch (Exception e) {
            log.error("保存监管码失败", e);
        }
//        List<String> billIds = doBills.stream().map(OmsDoBillHDO::getBillid).distinct().collect(toList());
//        callBackErpWhenTasksIsDone(billIds);
    }

    public int callBackErpWhenTasksIsDone(List<String> billIds) {
        List<Map<String, String>> list = pickTaskDMapper.getCheckStatusBySrcCode(billIds);
        if (CollUtil.isEmpty(list)) {
            return 0;
        }
        int count = list.size();
        Map<String, List<Map<String, String>>> maps = list.stream().collect(Collectors.groupingBy(m -> MapUtil.getStr(m, "billId")));
        for (Map.Entry<String, List<Map<String, String>>> entry : maps.entrySet()) {
            List<Map<String, String>> value = entry.getValue();
            if (value.stream().allMatch(m -> "5".equals(MapUtil.getStr(m, "checkStatus")))) {
                try {
                    pickTaskAppService.postBackErpByTable(billIds);
                } catch (Exception e) {
                    log.error("回传ERP失败", e);
                    count--;
                }
            }
        }
        return count;
    }

    private static void checkStatusByPickTasks(List<PickTaskD> ptDtls) {
        int taskConfirmed = Integer.parseInt(TASK_CONFIRMED.getCode());
        if (ptDtls.stream().anyMatch(t -> Integer.valueOf(t.getFlowStatus()) < taskConfirmed)) {
            throw new BizException("请先拣货");
        }
//        if (ptDtls.stream().anyMatch(t -> Integer.valueOf(t.getFlowStatus()) > taskConfirmed)) {
//            throw new BizException("请勿重复复核");
//        }
    }

    public void saveSuperVisionCode(OutboundCheckResultCallbackVO vo, OmsDoBillHDO omsDoBillHDO, Employee employee, List<PickTaskD> ptDtls) {

        List<OutboundCheckResultCallbackItemVO> subList = vo.getSubList();

        List<String> codeList = subList.stream().filter(s -> CollUtil.isNotEmpty(s.getDrugSupervisionCode())).map(s -> s.getDrugSupervisionCode()).flatMap(Collection::stream).collect(toList());

        if (CollUtil.isEmpty(codeList)) {
            return;
        }
        Set<String> itemIds = subList.stream().map(OutboundCheckResultCallbackItemVO::getItemId).collect(Collectors.toSet());
        List<BaseMtlItemMst> items = RestMsgHelper.getData(itemClient.getListByIds(itemIds));

        String[] lotIds = subList.stream().map(OutboundCheckResultCallbackItemVO::getLotId).toArray(String[]::new);
        List<BatchNumberListVO> lots = RestMsgHelper.getData(invClient.getBatchNumberBasicInfo(lotIds));

        DateTime now = DateUtil.date();
        List<SupervisionCode> list = codeList.stream().map(d -> {
            SupervisionCode supervision = new SupervisionCode();
            supervision.setId(String.valueOf(SnowFlakeUtils.getId()));
            supervision.setEnterpriseId(vo.getEnterpriseId());
            supervision.setWarehouseId(omsDoBillHDO.getBranchid());
            supervision.setWarehouseCode(omsDoBillHDO.getBranchcode());
            supervision.setCargoOwnerId(omsDoBillHDO.getConsignorid());
            supervision.setCargoOwnerCode(omsDoBillHDO.getConsignorcode());
            supervision.setBillno(omsDoBillHDO.getBillno());
            supervision.setSrcCode(omsDoBillHDO.getBillno());
            supervision.setBillType(omsDoBillHDO.getBilltype());
            supervision.setCreator(employee.getUserId());
            supervision.setCreatorName(employee.getUsername());
            supervision.setGmtCreate(now);
            supervision.setModifier(employee.getUserId());
            supervision.setModifierName(employee.getUsername());
            supervision.setGmtModified(now);
            supervision.setSupervisionCode(d);
            supervision.setLastUploadTime(now);
            supervision.setUnlock(0);
            supervision.setWhAreaCategoryCode("AGVL");
            supervision.setStage(6);
            supervision.setStatus("10");
            supervision.setPackLevel("2");
            supervision.setCodeType("1");
            supervision.setUploadTimes(1);
            supervision.setUploadFlag("0");
            supervision.setDownFlag(0);
            supervision.setSaveType(2);
            supervision.setScanDate(now);
            supervision.setScanName(employee.getUsername());
            supervision.setRefBillId(omsDoBillHDO.getBillid());
            supervision.setSupervisionType(Integer.valueOf(omsDoBillHDO.getBilltype()));

            subList.stream().filter(s -> s.getDrugSupervisionCode().contains(d)).findFirst().ifPresent(s -> {
                supervision.setItemId(s.getItemId());
                supervision.setPieceQty(s.getQty().toString());

                Optional.ofNullable(ptDtls).ifPresent(ps -> {
                    ps.stream().filter(p -> p.getPickTaskDId().equals(s.getTaskLineId())).findFirst().ifPresent(p ->
                            supervision.setRefBillLineId(p.getPickTaskDId()));
                });

                Optional.ofNullable(items).ifPresent(is -> {
                    is.stream().filter(i -> i.getItemId().equals(s.getItemId())).findFirst().ifPresent(i -> {
                        supervision.setItemCode(i.getItemCode());
                        supervision.setItemName(i.getItemName());
                        supervision.setPackSize(i.getCaseConversionRate().toPlainString());
                    });
                });

                Optional.ofNullable(lots).ifPresent(ls -> ls.stream().filter(l -> l.getBatchId().equals(s.getLotId())).findFirst().ifPresent(l -> supervision.setManufacturerLotNum(l.getManufacturerLotNum())));
            });
            return supervision;
        }).collect(toList());
        log.info("batchAddSupCode:{}", JSONObject.toJSONString(list));
        RestMsgHelper.getData(inBoundClient.batchAddSupCode(list));
    }

    @Override
    public void applyForDocumentPrinting(ApplyForDocumentPrintingVO vo) {
        log.info("EIS申请打印入参：{}",JSON.toJSONString(vo));
        List<String> barcodeList = vo.getBarcodes();
        if(barcodeList == null || barcodeList.size() <= 0){
            log.info("EIS申请打印面单，面单/标签不能为空！");
            return;
        }
        Criteria crth = Criteria.forClass(BarcodeHDO.class);
        Restriction res1 = Restrictions.in("barcode", barcodeList.toArray());
        crth.setRestriction(Restrictions.and(res1));
        List<BarcodeHDO> barcodes = barcodeHMapper.findByCriteria(crth);
//        List<BarcodeHDO> barcodes = barcodeHMapper.findFieldsByMap(FieldSelector.newInstance().include("barcodeType", "barcode"), MapUtils.put("billGroupId", vo.getBillNo()).put("warehouseId", vo.getWarehouseId()).put("isMerged", 1).getMap(), BarcodeHDO.class);
        if (CollUtil.isEmpty(barcodes)) {
            log.error("EIS申请打印面单，订单编号【{}】不存在", vo.getBillNo());
            return;
        }

        Map<String, List<BarcodeHDO>> maps = barcodes.stream().collect(Collectors.groupingBy(BarcodeHDO::getBarcodeType));
//        条码类型（0-标签 1-面单）
        List<BarcodeHDO> express = maps.get("1");
//        if (CollUtil.isNotEmpty(express)) {

            List<OmsDoBillHDO> bills = omsDoBillHMapper.findFieldsByMap(FieldSelector.newInstance().include("branchid", "consignorid", "barcode", "carrierCode", "attrStr10","carrierType"), MapUtils.put("billno", vo.getBillNo()).put("branchid", vo.getWarehouseId()).getMap(), OmsDoBillHDO.class);
            if (CollUtil.isEmpty(bills)) {
                log.error("EIS申请打印面单，订单编号【{}】不存在", vo.getBillNo());
                return;
            }
            if("1".equals(vo.getIsLfz())){
                Employee employee = RestMsgHelper.getData(powerResource.getByNum(vo.getEmployeeId(), vo.getWarehouseId(), vo.getEnterpriseId()));
                cn.hutool.core.lang.Assert.notNull(employee, "根据工号【{}】获取员工信息失败", vo.getEmployeeId());
                getUserDtoKeyAndSetCache(employee.getUsername());
            }

            OmsDoBillHDO omsDoBillHDO = bills.get(0);
            if("2".equals(omsDoBillHDO.getCarrierType())){
                pickTaskAppService.printBarcodes(barcodeList,omsDoBillHDO.getConsignorid(),omsDoBillHDO.getBranchid(),omsDoBillHDO.getBillno());
            }else {
                List<PrintParam> printParams = pickTaskAppService.printFaceOrder(barcodes, omsDoBillHDO.getConsignorid(), omsDoBillHDO.getBranchid(), omsDoBillHDO.getCarrierCode());
                if("1".equals(vo.getIsLfz())){
                  
                    RestMessage<?> restMessage = pickTaskAppService.print(printParams);
                    cn.hutool.core.lang.Assert.isTrue(restMessage.isSuccess(), "调用COMMON服务打印失败");
                }else {
                    print4GripByName(() -> {
                        RestMessage<?> restMessage = pickTaskAppService.print(printParams);

                        //保存打印日志
                        List<PrintLog> printLogs = new ArrayList<>();
                        for (PrintParam printDatum : printParams) {
                            PrintLog printLog = new PrintLog();
                            printLog.setPrintCode("faceOrder");
                            printLog.setBillno(omsDoBillHDO.getBillno());
                            printLog.setAttrStr3(printDatum.getParams().get("waybillCode").toString());
                            if(restMessage.isSuccess()){
                                printLog.setStatus("200");
                            }else {
                                printLog.setStatus("0");
                            }
                            printLogs.add(printLog);
                        }
                        printLogService.saveBatch(printLogs);

                        cn.hutool.core.lang.Assert.isTrue(restMessage.isSuccess(), "调用COMMON服务打印失败");
                    }, omsDoBillHDO.getAttrStr10());
                }
            }



    }

    @FunctionalInterface
    public interface PrintFunctional {
        void accept() throws BizException;
    }

    private void print4GripByName(PrintFunctional functional, String grip) {

        cn.hutool.core.lang.Assert.notEmpty(grip, "请先绑定格口信息");

        List<BaseCommonDict> dicts = RestMsgHelper.getData(commonClient.getDictBasicListByCodes("GRID_PRINT_RELATION", null));
        cn.hutool.core.lang.Assert.notEmpty(dicts, "请配置【GRID_PRINT_RELATION】格口打印策略关系");

        List<String> printName = null;
        try {
            printName = dicts.stream().filter(d -> StrUtil.splitTrim(d.getDictName(), ",").contains(grip)).map(BaseCommonDict::getDictCode).collect(toList());
        } catch (Exception e) {
            log.error("【GRID_PRINT_RELATION】格口关系请用逗号【,】隔开", e);
            throw new RuntimeException(e);
        }
        cn.hutool.core.lang.Assert.notEmpty(printName, "请先配置格口号：{}和打印策略关系", grip);
        cn.hutool.core.lang.Assert.isTrue(printName.size() == 1, "格口号：{}存在重复关系配置", grip);

        getUserDtoKeyAndSetCache(printName.get(0));
        functional.accept();
    }

    public UserDTO getUserDtoKeyAndSetCache(String printName) {
        log.info("getUserDtoKeyAndSetCache printName:{}", printName);

        HystrixRequestContext.initializeContext();
        HystrixVarUtil.setUserKey(printName);
        UserDTO userDTO = userTemplate.getUserDTO();
        log.info("getUserDtoKeyAndSetCache:{}", JSONObject.toJSONString(userDTO));
        if (userDTO != null) {
            return userDTO;
        }

        userDTO = new UserDTO();
        userDTO.setUsername(printName);
        setUser2Redis(printName, userDTO);
        return userDTO;
    }

    private void setUser2Redis(String printName, UserDTO userDTO) {
        AuthRedisProperties redis = authProperties.getRedis();
        redisTemplate.opsForValue().set(String.format("%s%s%s", redis.getNamespace(), redis.getPrefixAuth(), printName), userDTO, authProperties.getJwt().getExpiration(), TimeUnit.SECONDS);
    }

    @Override
    public void orderBindingGridFeedback(OrderBindingGridFeedbackVO vo) {
        String billNo = vo.getBillNo();
        cn.hutool.core.lang.Assert.notEmpty(billNo, "订单号不能为空");
        List<String> gridNos = vo.getGridNo();
        cn.hutool.core.lang.Assert.notEmpty(gridNos, "格口不能为空");
        String warehouseId = vo.getWarehouseId();
        cn.hutool.core.lang.Assert.notEmpty(warehouseId, "仓库ID不能为空");

        FieldSelector fs = FieldSelector.newInstance().include(new String[]{"attrStr10", "billid", "consignorid", "branchid","attrStr3","attrStr4"});
        List<OmsDoBillHDO> bills = omsDoBillHMapper.findFieldsByMap(fs, MapUtils.put("billno", vo.getBillNo()).put("branchid", warehouseId).getMap(), OmsDoBillHDO.class);
        cn.hutool.core.lang.Assert.notEmpty(bills, "订单号【{}】获取单据数据失败", vo.getBillNo());

        CompletableFuture<Void> futures = CompletableFuture.allOf(
                CompletableFuture.runAsync(() -> printQrReport(bills)),
                CompletableFuture.runAsync(() -> printSyInfo(bills)));
        try {
            futures.get();
        } catch (Exception e) {
            log.error("格口打印失败", e);
        }

        String gridNo = gridNos.stream().collect(Collectors.joining(","));
        TransactionHelper.persistenceErrorThrow(() -> {
            bills.forEach(b -> {
                b.setAttrStr10(gridNo);
                omsDoBillHMapper.updateFields(b, fs);
            });
        });
    }

    /**
     * 打印质检报告
     *
     * @param bills
     */
    public void printQrReport(List<OmsDoBillHDO> bills) {

        OmsDoBillHDO bill = bills.get(0);
        if(StringUtils.isBlank(bill.getAttrStr4()) || !"1".equals(bill.getAttrStr4())){
            return;
        }
        String branchid = bill.getBranchid();

        String printName = getPrintNameByBusiness(branchid, "imgManage-ZJBG-pdf");
        if (StrUtil.isNotEmpty(printName)) {
            getUserDtoKeyAndSetCache(printName);
        } else {
            initializePrinterName("printQrReport", bill);
        }

        bills.forEach(b -> {
            pickTaskAppService.printQrReport(b.getBillid(), b.getConsignorid(), b.getBranchid());
        });
    }

    private void initializePrinterName(String printName, OmsDoBillHDO bill) {
        HystrixRequestContext.initializeContext();
        HystrixVarUtil.setUserKey(printName);
        UserDTO userDTO = new UserDTO();
        userDTO.setUsername(printName);
        userDTO.setEnterpriseId(bill.getEnterpriseId());
        setUser2Redis(printName, userDTO);
    }

    /**
     * 打印首营报告
     *
     * @param bills
     */
    public void printSyInfo(List<OmsDoBillHDO> bills) {

        OmsDoBillHDO bill = bills.get(0);
        if(StringUtils.isBlank(bill.getAttrStr3()) || !"1".equals(bill.getAttrStr3())){
            return;
        }
        String branchid = bill.getBranchid();

        String printName = getPrintNameByBusiness(branchid, "imgManage-SYZL-pdf");
        if (StrUtil.isNotEmpty(printName)) {
            getUserDtoKeyAndSetCache(printName);
        } else {
            initializePrinterName("printSyInfo", bill);
        }

        bills.forEach(b -> {
            pickTaskAppService.printSyInfo(b.getBillid(), b.getConsignorid(), b.getBranchid());
        });
    }

    public String getPrintNameByBusiness(String warehouseId, String printBillCode) {
        PrintStrategyParam strategyParam = new PrintStrategyParam();
        strategyParam.setWarehouseId(warehouseId);
        strategyParam.setPrintBillCode(printBillCode);
        Page<SysPrintStrategy> pages = RestMsgHelper.getData(commonClient.strategylist(strategyParam));
        List<SysPrintStrategy> list = pages.getList();
        cn.hutool.core.lang.Assert.notEmpty(list, "获取【{}】打印策略失败", printBillCode);

        SysPrintStrategy strategy = list.get(0);
        log.info("listPersonStrategy:{}", JSONObject.toJSONString(strategy));

        List<SysPrintStrategyPerson> strategyPersons = RestMsgHelper.getData(commonClient.listPersonStrategy("", strategy.getConsignorId(), strategy.getPrintStrategy(), strategy.getStrategyId()));
        if (CollUtil.isNotEmpty(strategyPersons)) {
            List<BaseCommonDict> dicts = RestMsgHelper.getData(commonClient.getDictBasicListByCodes("GRID_APPOINT_PRINT_NAME", new String[]{"appoint-print"}));
            if (CollUtil.isNotEmpty(dicts)) {
                BaseCommonDict baseCommonDict = dicts.get(0);
                String printSolution = "";
                if ("imgManage-ZJBG-pdf".equals(printBillCode)) {
                    printSolution = baseCommonDict.getAttr1();
                } else if ("imgManage-SYZL-pdf".equals(printBillCode)) {
                    printSolution = baseCommonDict.getAttr2();
                } else {
                    return strategyPersons.get(0).getUsername();
                }
                String finalPrintSolution = printSolution;
                log.info("getPrintNameByBusiness printSolution:{}", printSolution);
                SysPrintStrategyPerson person = strategyPersons.stream().filter(sp -> sp.getPrintSolution().equals(finalPrintSolution)).findFirst().orElse(null);
                log.info("getPrintNameByBusiness SysPrintStrategyPerson:{}", JSONObject.toJSONString(strategyPersons));
                if (person != null) {
                    log.info("getPrintNameByBusiness return printName:{}", person.getPrintSolution());
                    return person.getPrintSolution();
                }
            }
            return strategyPersons.get(0).getUsername();
        }
        log.error("getPrintNameByBusiness strategyPersons is null");
        return null;
    }

    public void print(OmsDoBillHDO omsDoBillHDO, Employee employee) {
        //2.2.2.2，则根据拣货任务的实际拣货数量打印出库清单，发票(pdf，需要调上游系统接口，获取url)，以及该订单下所有明细的质检报告单；
        //打印出库清单
        if(omsDoBillHDO.getAttrNum4() == null || BigDecimal.ZERO.compareTo(omsDoBillHDO.getAttrNum4()) == 0){
            pickTaskAppService.printOutDetailList(omsDoBillHDO.getBillno(), omsDoBillHDO.getConsignorid(), omsDoBillHDO.getBranchid(),omsDoBillHDO.getAttrStr7());
        }
//        //获取发票
//        List<String> invoice = pickTaskAppService.getInvoice(omsDoBillHDO.getBillno());

//        TransactionHelper.persistenceErrorThrow(() -> {
//            //保存发票信息
//            pickTaskAppService.saveInvoice(invoice, omsDoBillHDO, employee.getUsername());
//        });
        if(!StringUtils.isBlank(omsDoBillHDO.getAttrStr5()) && "1".equals(omsDoBillHDO.getAttrStr5())){
            //打印发票信息
            pickTaskAppService.printInvoice(omsDoBillHDO.getBillno(), omsDoBillHDO.getConsignorid(), omsDoBillHDO.getBranchid());
        }

        //打印质检报告单
//        pickTaskAppService.printQrReport(omsDoBillHDO.getBillno(), omsDoBillHDO.getConsignorid(), omsDoBillHDO.getBranchid());

//        pickTaskAppService.printFaceOrder(bhs, omsDoBillHDO.getConsignorid(), omsDoBillHDO.getBranchid(), omsDoBillHDO.getCarrierCode());
    }

    private Map<String, Object> upCode(OmsDoBillHDO omsDoBillHDO) {
        //当前订单下的所有包裹复核完成后，根据订单对应的客户的资料维护的是否上传监管码字段，来识别是否调用上传码上放心平台接口；若是，则上传，若否，则不上传；
        boolean isUpCode = false;
        Map<String, Object> result = new HashMap<>();
        result.put("billId", omsDoBillHDO.getBillid());
        result.put("billtype", omsDoBillHDO.getBilltype());
        String shipperid = omsDoBillHDO.getShipperid();
        List<BaseCustomerMst> customerMsts = new ArrayList<>();
        BaseCustomerMstRequestVO customerMstRequestVO = new BaseCustomerMstRequestVO();
        customerMstRequestVO.setEnterpriseid(omsDoBillHDO.getEnterpriseId());
        customerMstRequestVO.setMasterId(shipperid);
        // 2 代表客户
        RestMessage<List<BaseCustomerMst>> restMessage = chainResource.findAll(customerMstRequestVO);
        if (restMessage.isSuccess() && CollUtil.isNotEmpty(restMessage.getData())) {
            customerMsts = restMessage.getData();
        }
        if (customerMsts.size() > 0) {
            if ("".equals(customerMsts.get(0).getIsQrCodeSupervise())) {
                isUpCode = true;
                result.put("isUpCode", isUpCode);
            }
        } else {
            // 查询供应商
            List<BaseSupplierMst> supplierMsts = new ArrayList<>();
            Set<String> supplierIds = new HashSet<>();
            supplierIds.add(shipperid);
            RestMessage<Map<String, BaseSupplierMst>> supplierMst = chainResource.getSupplierMstByIds(supplierIds);
            if (supplierMst.isSuccess() && CollUtil.isNotEmpty(supplierMst.getData())) {
                for (String s : supplierMst.getData().keySet()) {
                    supplierMsts.add(supplierMst.getData().get(s));
                }
            }
            if (supplierMsts.size() > 0) {
                if ("".equals(supplierMsts.get(0).getIsQrCodeSupervise())) {
                    isUpCode = true;
                    result.put("isUpCode", isUpCode);
                }
            } else {
                throw new BizException("查询订单客户失败!");
            }
        }
        return result;
    }

    private BarcodeHDO packBarCodeHdr(PickTaskH pickTaskH, DateTime now, Employee employee, String barCodeId, PickTaskD task) {
        BarcodeHDO barCodeHdr = new BarcodeHDO();
        barCodeHdr.setReportPrintCount(1);
        barCodeHdr.setOutboundPrintCount(1);
        barCodeHdr.setBldgId(pickTaskH.getBldgId());
        barCodeHdr.setBldgName(pickTaskH.getBldgName());
        barCodeHdr.setPrintCount(1);

        barCodeHdr.setPrintDate(now);
        Optional.ofNullable(employee).ifPresent(e -> {
            barCodeHdr.setPrintName(employee.getUsername());
            barCodeHdr.setCheckerId(employee.getUserId());
            barCodeHdr.setCheckerNo(employee.getJobnumber());
            barCodeHdr.setCheckerName(employee.getUsername());
            barCodeHdr.setModifier(employee.getUserId());
            barCodeHdr.setModifierName(employee.getUsername());
            barCodeHdr.setCreator(employee.getUserId());
            barCodeHdr.setCreatorName(employee.getUsername());
        });
        barCodeHdr.setCheckTime2(now);
        barCodeHdr.setCheckStatus("5");
        barCodeHdr.setId(barCodeId);
        barCodeHdr.setType("");
        barCodeHdr.setBarcode(String.valueOf(SnowFlakeUtils.getId()));
        barCodeHdr.setBarcodeType("1");
        barCodeHdr.setStatus('1');
        barCodeHdr.setWarehouseId(task.getWarehouseId());
        barCodeHdr.setBillGroupId(task.getSrcId());
        barCodeHdr.setEnterpriseId(task.getEnterpriseId());
        return barCodeHdr;
    }

    private List<BarCodeDDO> packBarCodeDtls(OutboundCheckResultCallbackVO vo, PickTaskD task, List<BaseMtlItemMst> items, String barCodeId, DateTime now, Employee employee) {
        return vo.getSubList().stream().map(v -> {
            BarCodeDDO bcDtl = new BarCodeDDO();
            bcDtl.setPrintCnt(1);
            bcDtl.setIsPiece(1);
            bcDtl.setContainerCode(task.getContainerCode());
            bcDtl.setItemId(v.getItemId());
            items.stream().filter(i -> i.getItemId().equals(bcDtl.getItemId())).findFirst().ifPresent(i -> {
                bcDtl.setItemCode(i.getItemCode());
            });
            bcDtl.setId(String.valueOf(SnowFlakeUtils.getId()));
            bcDtl.setBarcodeId(barCodeId);
            bcDtl.setWmsPickTaskDId(task.getSrcPickTaskDId());
            bcDtl.setQty(new BigDecimal(v.getQty().toString()));
            bcDtl.setWarehouseId(task.getWarehouseId());
            bcDtl.setCheckStatus("5");
            bcDtl.setEnterpriseId(task.getEnterpriseId());
            bcDtl.setGmtCreate(now);
            bcDtl.setGmtModified(now);
            Optional.ofNullable(employee).ifPresent(e -> {
                bcDtl.setModifier(employee.getUserId());
                bcDtl.setModifierName(employee.getUsername());
                bcDtl.setCreator(employee.getUserId());
                bcDtl.setCreatorName(employee.getUsername());
            });
            return bcDtl;
        }).collect(toList());
    }


    public List<Employee> getEmployees(String[] employeeNos, String warehouseId, String enterpriseId) {
        List<Employee> employees = Lists.newArrayList();
        for (String employeeNo : employeeNos) {
            Employee employee = RestMsgHelper.getData(powerResource.getByNum(employeeNo, warehouseId, enterpriseId));
            cn.hutool.core.lang.Assert.notNull(employee, "根据工号【{}】获取员工信息失败", employeeNo);
            employees.add(employee);
        }
        return employees;
    }

    public String[] isAllDone(List<PickTaskD> list1, List<PickTaskD> list2) {
        List<String> pickTaskIds = Lists.newArrayList();
        Map<String, List<PickTaskD>> maps1 = list1.stream().collect(Collectors.groupingBy(PickTaskD::getPickTaskId));
        Map<String, List<PickTaskD>> maps2 = list2.stream().collect(Collectors.groupingBy(PickTaskD::getPickTaskId));
        for (String pickTaskId : maps2.keySet()) {
            List<PickTaskD> tasks1 = maps1.get(pickTaskId);
            List<PickTaskD> tasks2 = maps2.get(pickTaskId);
            boolean isAllDone = tasks2.stream().allMatch(t -> tasks1.stream().map(PickTaskD::getPickTaskDId).collect(Collectors.toList()).contains(t.getPickTaskDId()));
            if (isAllDone) {
                pickTaskIds.add(pickTaskId);
            }
        }
        return pickTaskIds.toArray(new String[]{});
    }

    public List<InvStockPartCheckOut> packCostStockParams(List<PickTaskD> pendingTasks, List<WaveStorageDO> storages) {
        return pendingTasks.stream().map(pt -> {
            InvStockPartCheckOut out = new InvStockPartCheckOut();
            storages.stream().filter(s -> s.getId().equals(pt.getWaveStorageId())).findFirst().ifPresent(s -> {
                out.setBatchNum(s.getBatchNum());
            });
            out.setPickTaskDId(pt.getPickTaskDId());
            out.setLocatorId(pt.getLocatorId());
            //实际扣库存
            out.setQty(pt.getChecker2Qty());
//            out.setReturnToStockQty(pt.getSaleRedQty());
//            out.setContainerCode(pt.getContainerCode());
            out.setOutType("1");
            out.setItemId(pt.getItemId());

//            out.setContainerCodeSelectPreFlag(true);
            out.setLineBillIds(new String[]{pt.getBillDId()});
            out.setIsDestroy(false);
            return out;
        }).collect(Collectors.toList());
    }


    /*@Override
    public void printAll1(List<PrintAllVO> VOList) {
        AssertUtils.isNotEmpty(VOList, "请传入对应参数后打印");
        //面单打印
        List<PrintAllVO> waybillList = VOList.stream().filter(x -> ObjectUtils.isNotNull(x.getCarrierCode())).collect(toList());
        //标签打印
        List<PrintAllVO> barcodeList = VOList.stream().filter(x -> ObjectUtils.isNull(x.getCarrierCode())).collect(toList());

        List<PrintParam> printParamList = new ArrayList<>();
        //打印面单
        if(ObjectUtils.isNotNull(waybillList)) {
            for (PrintAllVO VO : waybillList) {
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                switch (VO.getCarrierCode()) {
                    case DoPrintConstant.DO_PRINT_SF://顺丰打印
                        PrintParam printParam1 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_SF);
                        printParamList.add(printParam1);
                        break;
                    case DoPrintConstant.DO_PRINT_JD://京东打印
                        PrintParam printParam2 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_JD);
                        printParamList.add(printParam2);
                        break;
                    case DoPrintConstant.DO_PRINT_DB://德邦打印
                        PrintParam printParam3 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_DB);
                        printParamList.add(printParam3);
                        break;
                    case DoPrintConstant.DO_PRINT_EMS://邮政打印
                        PrintParam printParam4 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_EMS);
                        printParamList.add(printParam4);
                        break;
                    case DoPrintConstant.DO_PRINT_YD://圆通打印
                        PrintParam printParam5 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_YD);
                        printParamList.add(printParam5);
                        break;
                    default:
                        log.info("没有查询到对应的面单打印商家:" + JSON.toJSONString(VO));
                        break;
                }
            }
        }
        //面单打印
        if(ObjectUtils.isNotNull(barcodeList)) {
            for (PrintAllVO VO : barcodeList) {
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                PrintParam printParam = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WMSBARCODEH);
                printParamList.add(printParam);
            }
        }

        if(!printParamList.isEmpty()) {
            log.info("批量补打入参：{}", JSON.toJSONString(printParamList));
            RestMessage<?> restMessage = commonClient.executePrint(printParamList);
            if(!restMessage.isSuccess()) {
                throw new RuntimeException("补打错误:" + restMessage.getMessage());
            }
            log.info("批量补打返回结果：{}", JSON.toJSONString(restMessage));
        }
    }*/

    @Override
    public Object printAll(List<PrintAllVO> VOList) {
        AssertUtils.isNotEmpty(VOList, "请传入对应参数后打印");
        //面单打印
        List<PrintAllVO> waybillList = VOList.stream().filter(x -> ObjectUtils.isNotNull(x.getCarrierCode())).collect(toList());
        //标签打印
        List<PrintAllVO> barcodeList = VOList.stream().filter(x -> ObjectUtils.isNull(x.getCarrierCode())).collect(toList());

        List<PrintParam> printParamList = new ArrayList<>();
        //打印面单
        if(ObjectUtils.isNotNull(waybillList)) {
            for (PrintAllVO VO : waybillList) {
                List<WmsFaceOrder> fields = wmsFaceOrderMapper.findByMap(MapUtils.put("waybillCode", VO.getBarcode()).getMap(), WmsFaceOrder.class);
                if (CollectionUtil.isEmpty(fields)) {
                    throw new RuntimeException("未查询到面单信息");
                }
                WmsFaceOrder wmsFaceOrder = fields.get(0);
                String carrierCode = "";
                if (StringUtil.isNotEmpty(wmsFaceOrder.getCancelFlag()) && !"1".equals(wmsFaceOrder.getCancelFlag())) {
                    carrierCode = wmsFaceOrder.getCancelFlag();
                } else {
                    carrierCode = VO.getCarrierCode();
                }
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                if ("SHUNFENGKUAIYUN".equals(carrierCode)) {
                    carrierCode = "SF";
                }
                if ("DEBANGWULIU".equals(carrierCode)) {
                    carrierCode = "DBL";
                }
                if ("YOUZHENGGUONEI".equals(carrierCode)) {
                    carrierCode = "EMS";
                }
                if ("JINGDONGKUAIYUN".equals(carrierCode)) {
                    carrierCode = "JD";
                }
                if ("YUNDAKUAIYUN".equals(carrierCode)) {
                    carrierCode = "YUNDA";
                }
                switch (carrierCode) {
                    case DoPrintConstant.DO_PRINT_SF://顺丰打印
                        PrintParam printParam1 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_SF);
                        printParamList.add(printParam1);
                        break;
                    case DoPrintConstant.DO_PRINT_JD://京东打印
                        PrintParam printParam2 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_JD);
                        printParamList.add(printParam2);
                        break;
                    case DoPrintConstant.DO_PRINT_DBL://德邦打印
                        PrintParam printParam3 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "DB");
                        printParamList.add(printParam3);
                        break;
                    case DoPrintConstant.DO_PRINT_EMS://邮政打印
                        PrintParam printParam4 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_EMS);
                        printParamList.add(printParam4);
                        break;
                    case DoPrintConstant.DO_PRINT_YUNDA://韵达打印
                        PrintParam printParam5 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "YD");
                        printParamList.add(printParam5);
                        break;
                    case DoPrintConstant.DO_PRINT_YUNDAPRO://韵达打印
                        PrintParam printParam6 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "YD");
                        printParamList.add(printParam6);
                        break;
                    default:
                        log.info("没有查询到对应的面单打印商家:" + JSON.toJSONString(VO));
                        break;
                }
            }
        }

        PrintParam printParam = new PrintParam();
        //面单打印
        if(ObjectUtils.isNotNull(barcodeList)) {
            for (PrintAllVO VO : barcodeList) {
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                printParam = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WMSBARCODEH);
                printParamList.add(printParam);
            }
        }


        log.info("批量补打入参：{}", JSON.toJSONString(printParamList));
        List<RestMessage> restMessageList = new ArrayList<>();
        RestMessage<?> restMessage = commonClient.executePrint(printParamList);
        restMessageList.add(restMessage);
        if(!restMessage.isSuccess()) {
            throw new RuntimeException("补打错误:" + restMessage.getMessage());
        }
        //List<RestMessage> restMessageList = new ArrayList<>();
        log.info("批量补打返回结果：{}", JSON.toJSONString(restMessage));
//        for (PrintParam param : printParamList) {
//            RestMessage<?> restMessage = commonClient.getPrintInfo(param);
//            restMessageList.add(restMessage);
//            if(!restMessage.isSuccess()) {
//                throw new RuntimeException("补打错误:" + restMessage.getMessage());
//            }
//            //List<RestMessage> restMessageList = new ArrayList<>();
//            log.info("批量补打返回结果：{}", JSON.toJSONString(restMessage));
//        }
        return restMessageList;
    }

    private PrintParam getPrintParam(String consignorId, String warehouseId, String barcode, String printBillCode) {
        PrintParam printParam = new PrintParam();
        printParam.setPrintBillCode(printBillCode);
        printParam.setParams(MapUtils.put("waybillCode", barcode).getMap());
        return printParam;
    }

    @TxTransaction(isStart = true)
    @Transactional(rollbackFor = Exception.class)
    public Object printAllTx(List<PrintAllVO> VOList) {
        AssertUtils.isNotEmpty(VOList, "请传入对应参数后打印");
        //查询barcodeh
        Criteria crth = Criteria.forClass(BarcodeHDO.class);
        List<String> barCodes = VOList.stream().map(PrintAllVO::getBarcode).collect(Collectors.toList());
        Restriction res11 = Restrictions.in("barcode", barCodes.toArray());
        crth.setRestriction(Restrictions.and(res11));
        List<BarcodeHDO> barcodeHDOS = barcodeHMapper.findByCriteria(crth);
        if (barcodeHDOS == null || barcodeHDOS.size() <= 0) {
            throw new BizException("查询条码表汇总失败!");
        }
        //面单打印
        List<PrintAllVO> waybillList = VOList.stream().filter(x -> ObjectUtils.isNotNull(x.getCarrierCode())).collect(toList());
        //标签打印
        List<PrintAllVO> barcodeList = VOList.stream().filter(x -> ObjectUtils.isNull(x.getCarrierCode())).collect(toList());

        List<PrintParam> printParamList = new ArrayList<>();

        //打印面单
        if(ObjectUtils.isNotNull(waybillList)) {
            for (PrintAllVO VO : waybillList) {
                List<WmsFaceOrder> fields = wmsFaceOrderMapper.findByMap(MapUtils.put("waybillCode", VO.getBarcode()).getMap(), WmsFaceOrder.class);
                if (CollectionUtil.isEmpty(fields)) {
                    throw new RuntimeException("未查询到面单信息");
                }
                WmsFaceOrder wmsFaceOrder = fields.get(0);
                String carrierCode = "";
                if (StringUtil.isNotEmpty(wmsFaceOrder.getCancelFlag()) && !"1".equals(wmsFaceOrder.getCancelFlag())) {
                    carrierCode = wmsFaceOrder.getCancelFlag();
                } else {
                    carrierCode = VO.getCarrierCode();
                }
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                if ("SHUNFENGKUAIYUN".equals(carrierCode)) {
                    carrierCode = "SF";
                }
                if ("DEBANGWULIU".equals(carrierCode)) {
                    carrierCode = "DBL";
                }
                if ("YOUZHENGGUONEI".equals(carrierCode)) {
                    carrierCode = "EMS";
                }
                if ("JINGDONGKUAIYUN".equals(carrierCode)) {
                    carrierCode = "JD";
                }
                if ("YUNDAKUAIYUN".equals(carrierCode)) {
                    carrierCode = "YUNDA";
                }
                switch (carrierCode) {
                    case DoPrintConstant.DO_PRINT_SF://顺丰打印
                        PrintParam printParam1 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_SF);
                        printParamList.add(printParam1);
                        break;
                    case DoPrintConstant.DO_PRINT_JD://京东打印
                        PrintParam printParam2 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_JD);
                        printParamList.add(printParam2);
                        break;
                    case DoPrintConstant.DO_PRINT_DBL://德邦打印
                        PrintParam printParam3 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "DB");
                        printParamList.add(printParam3);
                        break;
                    case DoPrintConstant.DO_PRINT_EMS://邮政打印
                        PrintParam printParam4 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + DoPrintConstant.DO_PRINT_EMS);
                        printParamList.add(printParam4);
                        break;
                    case DoPrintConstant.DO_PRINT_YUNDA://韵达打印
                        PrintParam printParam5 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "YD");
                        printParamList.add(printParam5);
                        break;
                    case DoPrintConstant.DO_PRINT_YUNDAPRO://韵达打印
                        PrintParam printParam6 = getPrintParam(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WAYBILLCODE + "YD");
                        printParamList.add(printParam6);
                        break;
                    default:
                        log.info("没有查询到对应的面单打印商家:" + JSON.toJSONString(VO));
                        break;
                }
            }
        }

        PrintParam printParam = new PrintParam();
        //面单打印
        if(ObjectUtils.isNotNull(barcodeList)) {
            for (PrintAllVO VO : barcodeList) {
                String consignorId = VO.getConsignorId();
                String warehouseId = VO.getWarehouseId();
                String barcode = VO.getBarcode();
                printParam = getPrintParamTx(consignorId, warehouseId, barcode, DoPrintConstant.DO_PRINT_WMSBARCODEH);
                printParamList.add(printParam);
            }
        }


        log.info("批量补打入参：{}", JSON.toJSONString(printParamList));
        List<RestMessage> restMessageList = new ArrayList<>();
        RestMessage<?> restMessage = commonClient.executePrint(printParamList);
        restMessageList.add(restMessage);
        if(!restMessage.isSuccess()) {
            throw new RuntimeException("补打错误:" + restMessage.getMessage());
        }
        //List<RestMessage> restMessageList = new ArrayList<>();

        log.info("批量补打返回结果：{}", JSON.toJSONString(restMessage));
//        for (PrintParam param : printParamList) {
//            RestMessage<?> restMessage = commonClient.getPrintInfo(param);
//            restMessageList.add(restMessage);
//            if(!restMessage.isSuccess()) {
//                throw new RuntimeException("补打错误:" + restMessage.getMessage());
//            }
//            //List<RestMessage> restMessageList = new ArrayList<>();
//            log.info("批量补打返回结果：{}", JSON.toJSONString(restMessage));
//        }
        List<PrintLog> printLogList = new ArrayList<>();
        for (BarcodeHDO barcodeHDO : barcodeHDOS) {
            PrintLog printLog = new PrintLog();
            printLog.setBillno(barcodeHDO.getBillGroupId());
            printLog.setAttrStr3(barcodeHDO.getBarcode());
            printLog.setPrintCode("faceOrder");
            if(restMessage.isSuccess()){
                printLog.setStatus("200");
            }else {
                printLog.setStatus("0");
            }
            printLogList.add(printLog);
        }
        printLogService.saveBatch(printLogList);
        return restMessageList;
    }

    private PrintParam getPrintParamTx(String consignorId, String warehouseId, String barcode, String printBillCode) {
        PrintParam printParam = new PrintParam();
        printParam.setPrintBillCode(printBillCode);
        printParam.setParams(MapUtils.put("waybillCode", barcode).getMap());
        return printParam;
    }

    /**
     * 零发整生成barcode
     * @param pickTaskH
     * @param omsDoBillHDO
     * @param pickTaskD
     * @param omsDoBillDDO
     * @param js
     */
    private List<String> lfzSavebarcodes(PickTaskH pickTaskH,OmsDoBillHDO omsDoBillHDO,PickTaskD pickTaskD,OmsDoBillDDO omsDoBillDDO,int js){
        List<BarcodeHDO> barCodeHDOs = new ArrayList<>();
        List<BarCodeDDO> barCodeDDOs = new ArrayList<>();
        for (int i = 0; i < js; i++) {
            BarcodeHDO barCodeHDO = new BarcodeHDO();
            barCodeHDO.setId(UUIDUtils.generateWithoutSeperator());

            if ("2".equals(omsDoBillHDO.getCarrierType())) {
                String barcode = BillUtils.getBarcode(redisTemplate);
                String maxBarcode = barcodeHMapper.getMaxBarcode();
                if (!StringUtils.isEmpty(maxBarcode) && Long.valueOf(maxBarcode) > Long.valueOf(barcode)) {
                    throw new BizException("标签号生成失败，不能重复生成!");
                }
                barCodeHDO.setBarcode(barcode);
                barCodeHDO.setBarcodeType("0");
            } else {
                barCodeHDO.setBarcode(null);
                barCodeHDO.setBarcodeType("1");
            }
            barCodeHDO.setBillGroupId(pickTaskH.getBillGroupId());
            barCodeHDO.setType("1"); // 整件拣选码
            barCodeHDO.setStatus('0');
            barCodeHDO.setWarehouseId(pickTaskH.getWarehouseId());
            barCodeHDO.setBldgId(pickTaskH.getBldgId());
            barCodeHDO.setBldgName(pickTaskH.getBldgName());
            ModelUtils.generateBaseData(barCodeHDO, userTemplate::getUserDTO);

            barCodeHDO.setWeight(omsDoBillDDO.getItemWeight().doubleValue());
            barCodeHDOs.add(barCodeHDO);

            BarCodeDDO barCodeDDO = new BarCodeDDO();
            barCodeDDO.setId(UUIDUtils.generateWithoutSeperator());
            ModelUtils.generateBaseData(barCodeDDO, userTemplate::getUserDTO);
            barCodeDDO.setBarcodeId(barCodeHDO.getId());
            barCodeDDO.setWmsPickTaskDId(pickTaskD.getPickTaskDId());
            barCodeDDO.setEnterpriseId(pickTaskH.getEnterpriseId());
            barCodeDDO.setWarehouseId(pickTaskH.getWarehouseId());
//            Map<String, String> itemMap = pickTaskHMapper.getItemCode(pickTaskD.getPickTaskDId(), pickTaskH.getWarehouseId());
//            if (itemMap != null && itemMap.containsKey("ITEM_ID")) {
//                barCodeDDO.setItemCode(itemMap.get("ITEM_CODE"));
//                barCodeDDO.setItemId(itemMap.get("ITEM_ID"));
//            }
            barCodeDDO.setItemCode(omsDoBillDDO.getItemcode());
            barCodeDDO.setItemId(omsDoBillDDO.getItemid());
            barCodeDDO.setIsPiece(0);
            barCodeDDO.setQty(omsDoBillDDO.getPackTypeNum());
            barCodeDDOs.add(barCodeDDO);
        }

        if(barCodeHDOs.size() > 0){
            barcodeHMapper.saveBatch(barCodeHDOs);
        }
        if(barCodeDDOs.size() > 0){
            barcodeDMapper.saveBatch(barCodeDDOs);
        }
        WaveBillDDO waveBillDDO = waveBillDMapper.findById(pickTaskD.getBillDId(), WaveBillDDO.class);
        if(waveBillDDO == null){
            throw new BizException("根据波次订单明细id:"+pickTaskD.getBillDId()+"查询失败!");
        }
        return pickTaskAppService.getLfzBarcodes(omsDoBillHDO,barCodeHDOs,barCodeDDOs,CollUtil.toList(waveBillDDO));
    }

    /**
     * 获取出库清单和发票打印节点
     * @return
     */
    private int getDetailAndInvoicePrintCode(){
        //根据通用参照打印节点判断是否打印出库清单和发票（1.拣货第一个任务确认后触发打印 2.整单拣货完成触发打印 3.复核完成打印）
        int printNode;
        RestMessage<List<BaseCommonDict>> printNodeRstMsg = commonClient.getDictBasicListByCodes("invoice_detail_print_node", null);
        if(printNodeRstMsg == null || !printNodeRstMsg.isSuccess() || printNodeRstMsg.getData() == null || printNodeRstMsg.getData().size() <= 0){
            printNode = 1;
        }else {
            printNode = Integer.parseInt(printNodeRstMsg.getData().get(0).getDictName());
        }
        return printNode;
    }

}
