package com.prolog.upcloud.base.wh.operate.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.codingapi.tx.annotation.TxTransaction;
import com.fasterxml.jackson.databind.JsonNode;
import com.prolog.cs.basic.chain.model.cargo.BaseCargoOwnerMst;
import com.prolog.cs.basic.common.model.BaseCommonDict;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.item.model.vo.ItemBaseInfoVO;
import com.prolog.cs.basic.warehouse.model.vo.ContainerQueryVO;
import com.prolog.cs.basic.warehouse.model.vo.WarehouseLocatorBasicInfo;
import com.prolog.cs.biz.outbound.model.dto.InfTaskOutBackDTO;
import com.prolog.entity.vo.*;
import com.prolog.enums.InventoryAuditEnum;
import com.prolog.enums.InventoryLockEnum;
import com.prolog.enums.OutBoundRequestEnum;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.common.integration.IntegrationApi;
import com.prolog.framework.bz.common.integration.IntegrationSearchData;
import com.prolog.framework.bz.core.model.ModelUtils;
import com.prolog.framework.bz.core.model.ModelUtils.OpType;
import com.prolog.framework.bz.core.util.ObjectUtils;
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.Criteria;
import com.prolog.framework.core.restriction.FieldSelector;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.lock.annotation.RepeatOperationLock;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.JsonUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.SnowFlakeUtils;
import com.prolog.inte.EisHandler;
import com.prolog.upcloud.base.inventory.vo.*;
import com.prolog.upcloud.base.inventory.vo.StockLotLockVO;
import com.prolog.upcloud.base.wh.operate.constant.CheckStatusEnum;
import com.prolog.upcloud.base.wh.operate.core.RestMsgHelper;
import com.prolog.upcloud.base.wh.operate.dao.WmsInvCheckDMapper;
import com.prolog.upcloud.base.wh.operate.dao.WmsInvCheckDReMapper;
import com.prolog.upcloud.base.wh.operate.dao.WmsInvCheckHMapper;
import com.prolog.upcloud.base.wh.operate.model.*;
import com.prolog.upcloud.base.wh.operate.resource.*;
import com.prolog.upcloud.base.wh.operate.service.AdjustService;
import com.prolog.upcloud.base.wh.operate.service.InvCheckService;
import com.prolog.upcloud.base.wh.operate.service.UserService;
import com.prolog.upcloud.base.wh.operate.utils.BeanConvertUtils;
import com.prolog.upcloud.base.wh.operate.utils.StringUtils;
import com.prolog.upcloud.base.wh.operate.utils.TransactionHelper;
import com.prolog.upcloud.base.wh.operate.vo.*;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

import static com.prolog.upcloud.base.wh.operate.constant.EisConstant.*;
import static com.prolog.upcloud.base.wh.operate.constant.WhOperataConstant.PICK_MODE_DEVICE;

;

/**
 * @author zzz
 * @desc 盘点
 * @date 2021/4/7
 */
@Service
public class InvCheckServiceImpl implements InvCheckService {

    private static Logger logger = LoggerFactory.getLogger(InvCheckServiceImpl.class);

    @Autowired
    private WmsInvCheckHMapper invCheckHMapper;

    @Autowired
    private WmsInvCheckDMapper invCheckDMapper;

    @Autowired
    private AdjustService adjustService;

    @Autowired
    private UserService userService;

    @Autowired
    CommonResource commonResource;

    @Autowired
    StockResource stockResource;

    @Autowired
    ItemResource itemResource;

    @Autowired
    WarehouseClient warehouseClient;

    @Autowired
    ChainResource chainResource;

    @Autowired
    WmsInvCheckDReMapper invCheckDReMapper;

    @Autowired
    private IntegrationApi integrationApi;

    @Value("${prolog.integration.instockTransforId:314}")
    private String instockTransforId;

    @Value("${prolog.integration.countSheetId:299}")
    private String countSheetId;

    @Value("${prolog.integration.countSheetInId:300}")
    private String countSheetInId;

    @Value("${prolog.integration.countSheetOutId:301}")
    private String countSheetOutId;

    @Autowired
    private WarehouseClient warehouseResource;
    @Resource
    private EisHandler eisHandler;
    @Resource
    private UserTemplate userTemplate;

    /**
     * 新增盘点计划
     *
     * @param invCheckAddVO 入参
     */
    @Override
    @Transactional
    @TxTransaction(isStart = true)
    @RepeatOperationLock(timeOut = 500)
    public void addInvCheck(WmsInvCheckAddVO invCheckAddVO) {
        // 点击按钮增加校验：校验EIS有无设置对应的盘点站台（调用接口EIS站台设置，接口待确认），若无则提示“EIS未设置对应盘点站台，不能生成盘点计划”
        //        String cargoOwnerId = invCheckAddVO.getCargoOwnerId();
        //        if(StringUtils.isEmpty(cargoOwnerId))
        //            throw new ParameterException("货主不能为空！");
        //        if(StringUtils.isEmpty(invCheckAddVO.getWarehouseId()))
        //            throw new ParameterException("仓库不能为空！");
        if (StringUtils.isEmpty(invCheckAddVO.getCheckMethod()))
            throw new ParameterException("盘点方式不能为空！");
        if (StringUtils.isEmpty(invCheckAddVO.getCheckType()))
            throw new ParameterException("盘点类型不能为空！");
        List<WmsInvCheckDVO> invCheckDVOList = invCheckAddVO.getInvCheckDVOList();
        if (invCheckDVOList == null || invCheckDVOList.isEmpty())
            throw new ParameterException("请选择明细！");
        Date date = new Date();
        UserDTO userDTO = userTemplate.getUserDTO();
        String userId = userDTO.getId();
        String userName = userDTO.getNickname();
        String enterpriseId = userDTO.getEnterpriseId();

        String cargoOwnerId = invCheckDVOList.get(0).getCargoOwnerId();
        String warehouseId = invCheckDVOList.get(0).getWarehouseId();

        WmsInvCheckH wmsInvCheckH = new WmsInvCheckH();
        String checkHeaderId = String.valueOf(SnowFlakeUtils.getId());// 主表id
        wmsInvCheckH.setCheckHeaderId(checkHeaderId);
        wmsInvCheckH.setAutoBillNum(checkHeaderId);
        wmsInvCheckH.setAccessLevel("9");
        wmsInvCheckH.setWarehouseId(warehouseId);
        //        wmsInvCheckH.setDcId(invCheckAddVO.getDcId());
        wmsInvCheckH.setCargoOwnerId(cargoOwnerId);
        wmsInvCheckH.setCheckMethod(invCheckAddVO.getCheckMethod());
        wmsInvCheckH.setCheckType(invCheckAddVO.getCheckType());
        wmsInvCheckH.setCheckType("0"); // 默认为计划盘点
        wmsInvCheckH.setCheckDate(date);
        wmsInvCheckH.setEnterpriseId(enterpriseId);
        wmsInvCheckH.setStatus("NEW");
        wmsInvCheckH.setPostFlag("Y");
        wmsInvCheckH.setBatchFlag("Y");
        wmsInvCheckH.setCreator(userId);
        wmsInvCheckH.setCreatorName(userName);
        wmsInvCheckH.setGmtCreate(date);
        wmsInvCheckH.setModifier(userId);
        wmsInvCheckH.setModifierName(userName);
        wmsInvCheckH.setGmtModified(date);
        invCheckHMapper.save(wmsInvCheckH);

        List<WmsInvCheckD> list = new ArrayList<>();
        BigDecimal zero = BigDecimal.ZERO;
        BigDecimal one = BigDecimal.ONE;
        int lineNum = 1;
        // 生成盘点预占入参
        List<InvStockAdjust> invStockList = new ArrayList<>();
        for (WmsInvCheckDVO wmsInvCheckDVO : invCheckDVOList) {
            WmsInvCheckD model = new WmsInvCheckD();
            BeanUtils.copyProperties(wmsInvCheckDVO, model);
            model.setPieceQuantityFact(zero);
            model.setCaseQuantityFact(zero);
            model.setOddQuantityFact(zero);
            model.setQuantityDiff(zero);
            model.setCreator(userId);
            model.setCreatorName(userName);
            model.setGmtCreate(date);
            model.setModifier(userId);
            model.setModifierName(userName);
            model.setGmtModified(date);
            model.setCheckHeaderId(checkHeaderId);
            model.setStatus("0");
            model.setOperBy(userName);
            model.setLineNum(lineNum++);
            model.setEnterpriseId(enterpriseId);
            // 解决saveBatch 其中某一项为空时,无法插入的问题
            BigDecimal caseQuantityAccount = model.getCaseQuantityAccount();
            if (caseQuantityAccount == null) {
                model.setCaseQuantityAccount(zero);
            }
            BigDecimal conversionRate = model.getConversionRate();
            if (conversionRate == null) {
                model.setConversionRate(one);
            }
            BigDecimal oddQuantityAccount = model.getOddQuantityAccount();
            if (oddQuantityAccount == null) {
                model.setOddQuantityAccount(zero);
            }
            String uom = model.getUom();
            if (StringUtils.isBlank(uom)) {
                model.setUom("无");
            }
            String manufacturerLotNum = model.getManufacturerLotNum();
            if (StringUtils.isBlank(manufacturerLotNum)) {
                model.setManufacturerLotNum("");
            }
            invCheckDMapper.save(model);
            list.add(model);

            // 构建生成盘点预占入参
            this.excutePreStock(invStockList, wmsInvCheckH, model);
        }

        if (ObjectUtils.isEmpty(invStockList)) {
            return;
        }
        // 生成盘点预占
        RestMessage adjustStock = stockResource.adjustStock(invStockList);
        if (adjustStock != null && !adjustStock.isSuccess()) {
            throw new BizException("调用库存预占失败!原因->" + adjustStock.getMessage());
        }

        String[] locatorIdList = list.stream().map(WmsInvCheckD::getWhLocatorId).toArray(String[]::new);
        List<WarehouseLocatorBasicInfo> locationList = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locatorIdList));
        if (CollUtil.isEmpty(locationList)) {
            throw new BizException("根据货位ID没有查询到货位信息！");
        }
        Set<String> itemidSet = list.stream().map(WmsInvCheckD::getItemId).filter(StringUtils::isNotEmpty).collect(Collectors.toSet());
        RestMessage<List<BaseMtlItemMst>> itemMsg = itemResource.getListByIds(itemidSet);
        if (!itemMsg.isSuccess() || CollUtil.isEmpty(itemMsg.getData())) {
            throw new BizException("查询商品信息失败！");
        }
        List<InventoryLockVO> lockList = new ArrayList<>();
        for (WmsInvCheckD invCheckD : list) {
            WarehouseLocatorBasicInfo locator = locationList.stream().filter(loc -> loc.getWarehouseLocatorId().equals(invCheckD.getWhLocatorId())).findFirst().orElse(null);
            if (null == locator) {
                throw new BizException("根据货位ID没有查询到货位信息！");
            }
            // 设置商品相关
            String itemId = invCheckD.getItemId();
            BaseMtlItemMst itemMst = itemMsg.getData().stream().filter(var -> var.getItemId().equals(itemId)).findFirst().orElse(null);
            if (null == itemMst) {
                throw new BizException("查询商品信息失败！");
            }
            // 如果存在设备库的盘点任务，需要推送库存锁定接口至EIS锁定库存
            if (!PICK_MODE_DEVICE.equals(locator.getPickMode())) {
                continue;
            }
            InventoryLockVO inventoryLockVO = new InventoryLockVO();
            inventoryLockVO.setWarehouseId(wmsInvCheckH.getWarehouseId());
            inventoryLockVO.setItemId(itemId);
            // 锁定库存
            inventoryLockVO.setConfirmQty(invCheckD.getPieceQuantityAccount().doubleValue());
            if (StringUtils.isNotBlank(invCheckD.getContainerCode()) && !"N/A".equals(invCheckD.getContainerCode())) {
                inventoryLockVO.setContainerNo(invCheckD.getContainerCode());
            }
            inventoryLockVO.setWmsLocationCode("MJK".equals(locator.getWarehouseAreaCode()) ? "MJZ" : locator.getWarehouseAreaCode());
            inventoryLockVO.setOwnerId(wmsInvCheckH.getCargoOwnerId());
            inventoryLockVO.setLotId(invCheckD.getBatchId());
            inventoryLockVO.setWorkType(InventoryLockEnum.INV_LOCK.getWorkType());
            inventoryLockVO.setBusinessType(InventoryLockEnum.INV_LOCK.getBusinessType());
            String id = String.valueOf(SnowFlakeUtils.getId());
            inventoryLockVO.setMsgId(id);
            inventoryLockVO.setTaskId(wmsInvCheckH.getCheckHeaderId());
            inventoryLockVO.setTaskLineId(invCheckD.getCheckLineId());
            if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
                String packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
                inventoryLockVO.setPackId(packId);
            }
            lockList.add(inventoryLockVO);
        }
        if (CollUtil.isNotEmpty(lockList)) {
            logger.info("生成盘点任务库存锁定回传eis入参:{}", JSONObject.toJSONString(lockList));
            eisHandler.inventoryLock(lockList);
        }

        //// 库存盘点集合
        //List<Map<String, Object>> inventoryList = getIssueDataList(locationBasicInfos, invCheckAddVO, list);
        //// 如果下发盘点集合不为空，则调用下发接口;
        //Map<String, Object> resultData = new HashMap<>();
        //String resultStr = "";
        //if (CollectionUtil.isNotEmpty(inventoryList)) {
        //    if (!ObjectUtils.isNull(inventoryList)) {
        //        resultData.put("resultData", inventoryList);
        //        IntegrationSearchData sd = new IntegrationSearchData();
        //        sd.setInterfaceId(countSheetInId);
        //        sd.setData(resultData);
        //        try {
        //            logger.info("发送参数:", JsonUtils.toString(sd));
        //            resultStr = integrationApi.searchForJsonStr(sd);
        //            logger.info("盘点单下发返回参数:", JsonUtils.toString(resultStr));
        //        } catch (IntegrationSearchException e) {
        //            throw new BizException("发送数据失败");
        //        } catch (JsonProcessingException e) {
        //            throw new BizException("发送数据失败");
        //        }
        //    } else {
        //        throw new BizException("发送数据为空");
        //    }
        //
        //    // 更新盘点行的状态为agv盘点 BY xiong
        //    Set<String> collect = inventoryList.stream().map(p -> (String) p.get("taskId")).collect(Collectors.toSet());
        //    Criteria crt = Criteria.forClass(WmsInvCheckD.class);
        //    crt.setRestriction(Restrictions.in("checkLineId", collect.toArray()));
        //    invCheckDMapper.updateMapByCriteria(MapUtils.put("status", "2").getMap(), crt); // 发送给agv盘点状态
        //
        //    if (collect.size() == invCheckDVOList.size()) {
        //        // 如果数量相同,更新头表状态
        //        String checkHeaderId2 = wmsInvCheckH.getCheckHeaderId();
        //        invCheckHMapper.updateMapById(checkHeaderId2, MapUtils.put("status", "TOAGV").getMap(), WmsInvCheckH.class);
        //    }
        //
        //}
        //		invCheckDMapper.saveBatch(list);
    }

    /**
     * 生成盘点任务预占库存
     *
     * @param invStockList 预占库存入参
     * @param invCheckH 盘点汇总
     * @param model 盘点明细
     */
    private void excutePreStock(List<InvStockAdjust> invStockList, WmsInvCheckH invCheckH, WmsInvCheckD model) {
        InvStockAdjust adjust = new InvStockAdjust();
        adjust.setBillId(invCheckH.getCheckHeaderId());
        adjust.setLineBillId(model.getCheckLineId());
        adjust.setWarehouseId(invCheckH.getWarehouseId());

        InvStockAdjustDetail adjustD = new InvStockAdjustDetail();
        adjustD.setBatchId(model.getBatchId());
        adjustD.setComments(model.getComments());
        String containerCode = model.getContainerCode();
        if (StringUtils.isEmpty(containerCode)) {
            containerCode = "N/A";
        }
        adjustD.setContainerCode(containerCode);
        String goodsCaseCode = model.getGoodsCaseCode();
        if (StringUtils.isEmpty(goodsCaseCode)) {
            goodsCaseCode = "N/A";
        }
        adjustD.setGoodsCaseCode(goodsCaseCode);
        adjustD.setLocatorId(model.getWhLocatorId());
        adjustD.setQuantity(model.getPieceQuantityAccount().negate());
        adjustD.setStatus(model.getStockStatus());
        List<InvStockAdjustDetail> adjustDList = new ArrayList<>();
        adjustDList.add(adjustD);
        adjust.setDetails(adjustDList);
        invStockList.add(adjust);
    }

    /**
     * 盘点录入保存，生成差异
     *
     * @param list
     */
    @Override
    @RepeatOperationLock(timeOut = 500)
    @Transactional(rollbackFor = Exception.class)
    public void updateInvCheck(List<WmsInvCheckUpdateVO> list) {

        String[] checkLineIds = list.stream().map(WmsInvCheckUpdateVO::getCheckLineId).toArray(String[]::new);
        Assert.notEmpty(checkLineIds, "盘点明细ID不能为空");

        List<WarehouseLocatorBasicInfo> locatorBasicInfos = new ArrayList<>();

        List<WmsInvCheckD> deviceCheckDs = checkIsDeviceNotSend(checkLineIds, locatorBasicInfos);

        updateCheckD(list, locatorBasicInfos, checkLineIds);

        invCheckHMapper.updateCheckDoneStatus(checkLineIds);

        if (CollUtil.isNotEmpty(deviceCheckDs)) {
            this.generateFinishTaskVO(deviceCheckDs, list);
        }
    }

    /**
     * 封装EIS作业完成确认参数
     */
    private void generateFinishTaskVO(List<WmsInvCheckD> list, List<WmsInvCheckUpdateVO> sourceList) {

        String hrdId = list.stream().map(WmsInvCheckD::getCheckHeaderId).findFirst().orElse(null);
        Assert.notBlank(hrdId, "获取盘点单失败");
        WmsInvCheckH checkH = invCheckHMapper.findById(hrdId, WmsInvCheckH.class);
        Assert.notNull(checkH, "获取盘点单失败");

        Set<String> itemIds = list.stream().map(WmsInvCheckD::getItemId).collect(Collectors.toSet());
        List<BaseMtlItemMst> items = RestMsgHelper.unpack(itemResource.getListByIds(itemIds));

        Set<String> locatorIds = list.stream().map(WmsInvCheckD::getWhLocatorId).collect(Collectors.toSet());
        List<WarehouseLocatorBasicInfo> locators = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locatorIds.toArray(new String[]{})));

        // 需要回传的货位
        Set<String> backLocators = locators.stream().filter(var -> var.getWarehouseAreaCategory().equals("AGVZ") || var.getWarehouseAreaCategory().equals("MJK")
                        || var.getWarehouseAreaCategory().equals("AGVSP") || var.getWarehouseAreaCategory().equals("AGVQX") || var.getWarehouseAreaCategory().equals("AGVZY"))
                .map(WarehouseLocatorBasicInfo::getWarehouseLocatorId).collect(Collectors.toSet());
        if (CollUtil.isEmpty(backLocators)) {
            //没有需要回传的数据
            return;
        }
        List<WmsInvCheckD> backList = list.stream().filter(var -> backLocators.contains(var.getWhLocatorId())).collect(Collectors.toList());
        if (CollUtil.isEmpty(backList)) {
            //没有需要回传的数据
            return;
        }
        List<String> containCodes = backList.stream().map(WmsInvCheckD::getContainerCode).distinct().collect(Collectors.toList());
        for (String containCode : containCodes) {
            List<WmsInvCheckD> dList = backList.stream().filter(d -> d.getContainerCode().equals(containCode) && OUTBOUND_INSTRUCT_DELIVERY.equals(d.getOutboundInstruct())).collect(Collectors.toList());
            if (!dList.isEmpty()) {
                this.generateTaskFinishedConfirmSubListVO(containCode, dList, items, locators, sourceList);
            }
        }
    }

    private void generateTaskFinishedConfirmSubListVO(
            String containerCode,
            List<WmsInvCheckD> dList,
            List<BaseMtlItemMst> items,
            List<WarehouseLocatorBasicInfo> locators,
            List<WmsInvCheckUpdateVO> sourceList
    ) {
        OperationCompleteVO completeVO = new OperationCompleteVO();
        completeVO.setMsgId(IdUtil.fastSimpleUUID());
        completeVO.setContainerNo(containerCode);
        completeVO.setBhFlag("0");
        List<OperationCompleteItemVO> subList = new ArrayList<>();

        for (WmsInvCheckD wmsInvCheckD : dList) {
            BaseMtlItemMst itemMst = items.stream().filter(var -> wmsInvCheckD.getItemId().equals(var.getItemId())).findFirst().orElse(null);
            WarehouseLocatorBasicInfo locator = locators.stream().filter(var -> var.getWarehouseLocatorId().equals(wmsInvCheckD.getWhLocatorId())).findFirst().orElse(null);

            WmsInvCheckUpdateVO sourceCheck = sourceList.stream().filter(source -> wmsInvCheckD.getCheckLineId().equals(source.getCheckLineId())).findFirst().orElse(null);

            OperationCompleteItemVO itemVO = new OperationCompleteItemVO();
            itemVO.setBillNo(wmsInvCheckD.getCheckHeaderId());
            itemVO.setTaskId(wmsInvCheckD.getCheckHeaderId());
            itemVO.setWarehouseId(locator.getWarehouseId());
            itemVO.setEnterpriseId(wmsInvCheckD.getEnterpriseId());
            itemVO.setWorkType(OutBoundRequestEnum.INV_PLANCHECK.getWorkType());
            itemVO.setBusinessType(OutBoundRequestEnum.INV_PLANCHECK.getBusinessType());
            itemVO.setTaskLineId(wmsInvCheckD.getCheckLineId());
            itemVO.setOwnerId(wmsInvCheckD.getCargoOwnerId());
            itemVO.setItemId(wmsInvCheckD.getItemId());
            itemVO.setLotId(wmsInvCheckD.getBatchId());
            String packId = "";
            if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
                packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
            }
            itemVO.setPackId(packId);
            itemVO.setWmsLocationCode("MJK".equals(locator.getWarehouseAreaCode()) ? "MJZ" : locator.getWarehouseAreaCode());
            itemVO.setQty(sourceCheck.getPieceQuantityFact().toString());
            itemVO.setInventoryQty(sourceCheck.getPieceQuantityAccount().doubleValue());
            itemVO.setIsLock(sourceCheck.getPieceQuantityFact().compareTo(wmsInvCheckD.getPieceQuantityAccount()) == 0 ? "0" : "1");
            itemVO.setIsCheck("1");
            subList.add(itemVO);
        }
        completeVO.setSubList(subList);

//        ContainerConfirmDto vo = new ContainerConfirmDto();
//        vo.setContainerNo(containerCode);
//        vo.setContainerType("3");
//
//        List<EisConfirmSubVo> confirmVOS = new ArrayList<>();
//        for (WmsInvCheckD wmsInvCheckD : dList) {
//            BaseMtlItemMst itemMst = items.stream().filter(var -> wmsInvCheckD.getItemId().equals(var.getItemId())).findFirst().orElse(null);
//            WarehouseLocatorBasicInfo locator = locators.stream().filter(var -> var.getWarehouseLocatorId().equals(wmsInvCheckD.getWhLocatorId())).findFirst().orElse(null);
//            if (null == itemMst) {
//                throw new BizException("商品信息不存在！");
//            }
//            if (null == locator) {
//                throw new BizException("查询货位信息失败！");
//            }
//            EisConfirmSubVo subVo = new EisConfirmSubVo();
//            subVo.setMsgId(IdUtil.fastSimpleUUID());
//            subVo.setTaskId(wmsInvCheckD.getCheckHeaderId());
//            subVo.setSeqNo(wmsInvCheckD.getCheckLineId());
//            subVo.setBusinessType("30");
//            subVo.setWorkType("30");
//            subVo.setItemId(wmsInvCheckD.getItemId());
//            subVo.setLotId(wmsInvCheckD.getBatchId());
//            subVo.setOwnerId(wmsInvCheckD.getCargoOwnerId());
//            String packId = "";
//            if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
//                packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
//            }
//            subVo.setPackId(packId);
//            subVo.setWarehouseId("JXYJ");
//            subVo.setWmslocationCode(locator.getWarehouseLocatorCode());
//            subVo.setInventoryQty(wmsInvCheckD.getPieceQuantityAccount());
//            subVo.setCountQty(wmsInvCheckD.getPieceQuantityFact());
//            subVo.setIsLock(wmsInvCheckD.getPieceQuantityAccount().compareTo(wmsInvCheckD.getPieceQuantityFact()) != 0 ? "1" : "0");
//
//            confirmVOS.add(subVo);
//        }
//        vo.setSubList(confirmVOS);
        logger.info("generateTaskFinishedConfirmSubListVO-盘点作业完成推送EIS入参：->{}", JSONObject.toJSONString(completeVO));
        // FIXME:封装正确参数
        eisHandler.operationComplete(Collections.singletonList(completeVO));

        //释放容器
        ContainerQueryVO containerQueryVO = new ContainerQueryVO();
        containerQueryVO.setContainerCode(containerCode);
        containerQueryVO.setEnterpriseId(dList.get(0).getEnterpriseId());
        containerQueryVO.setWarehouseId(locators.get(0).getWarehouseId());
        RestMessage<Object> release = warehouseResource.release(containerQueryVO);
        logger.info("托盘库存已经为0，托盘解锁->{},{}", JSONObject.toJSONString(containerQueryVO), JSONObject.toJSONString(release));

//        stockResource.askIntegration(new AskIntegrationVo("confirmContainer", vo));
    }

    /**
     * 检查立库是否发送出库指令
     *
     * @param checkLineIds 检查线id
     */
    private List<WmsInvCheckD> checkIsDeviceNotSend(String[] checkLineIds, List<WarehouseLocatorBasicInfo> warehouseLocatorBasicInfos) {
        List<WmsInvCheckD> dList = invCheckDMapper.findByIds(WmsInvCheckD.class, checkLineIds, null);
        Assert.notEmpty(dList, "获取盘点明细失败");
        WmsInvCheckD processedList = dList.stream().filter(d -> (!"0".equals(d.getStatus()) && !"30".equals(d.getStatus()))).findFirst().orElse(null);
        if (processedList != null) {
            throw new BizException(String.format("单据编号【%s】已保存录入，请刷新页面", processedList.getCheckHeaderId()));
        }

        String[] locationIds = dList.stream().map(WmsInvCheckD::getWhLocatorId).toArray(String[]::new);
        Assert.notEmpty(locationIds, "获取货位信息失败");

        List<WarehouseLocatorBasicInfo> locations = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locationIds));
        warehouseLocatorBasicInfos.addAll(locations);

        List<WmsInvCheckD> deviceCheckDList = dList.stream().filter(d -> isDevice(d.getWhLocatorId(), locations)).collect(Collectors.toList());
        if (CollUtil.isEmpty(deviceCheckDList)) {
            return Collections.emptyList();
        }

        WmsInvCheckD unSendCheckD = deviceCheckDList.stream().filter(d -> !OUTBOUND_INSTRUCT_DELIVERY.equals(d.getOutboundInstruct())).findFirst().orElse(null);
        if (unSendCheckD != null) {
            throw new PrologException(String.format("托盘号【%s】未出库不能盘点录入操作", unSendCheckD.getContainerCode()));
        }
        return deviceCheckDList;
    }

    private void updateCheckD(List<WmsInvCheckUpdateVO> list, List<WarehouseLocatorBasicInfo> locatorBasicInfos, String[] checkLineIds) {
        int row = 0;
        Date now = new Date();
//        List<InventoryAuditVO> toEisVos = new ArrayList<>();
        List<WmsInvCheckD> invCheckDS = invCheckDMapper.findByIds(WmsInvCheckD.class, checkLineIds, null);
        Set<String> itemIds = invCheckDS.stream().map(WmsInvCheckD::getItemId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        RestMessage<List<BaseMtlItemMst>> itemMsg = itemResource.getListByIds(itemIds);
        if (!itemMsg.isSuccess() || CollUtil.isEmpty(itemMsg.getData())) {
            throw new BizException("查询商品信息失败！");
        }
        for (WmsInvCheckUpdateVO model : list) {
            WmsInvCheckD wmsInvCheckD = invCheckDS.stream().filter(var -> var.getCheckLineId().equals(model.getCheckLineId())).findFirst().orElse(null);
            UserDTO user = new UserDTO();
            if (StringUtils.isEmpty(model.getType())) {
                user = userService.getUser();
            } else {
                user.setId("");
                user.setUsername("EIS");
            }
            row++;
            if (model.getCaseQuantityFact() == null || model.getOddQuantityFact() == null) {
                throw new ParameterException(String.format("第[%d]行,操作的数量不可为空!", row));
            }
            BigDecimal pieceQuantityFact = model.getPieceQuantityFact();
            BigDecimal pieceQuantityAccount = model.getPieceQuantityAccount();
            AssertUtils.notNull(pieceQuantityFact, "实际盘点数量不可为空!");
            AssertUtils.notNull(pieceQuantityAccount, "帐存数量不可为空!");
            if (pieceQuantityFact.compareTo(pieceQuantityAccount) > 0) {
                throw new ParameterException("盘点单【" + model.getCheckLineId() + "】实盘数量大于库存数量，不允许盘盈！");
            }
            // 更新复盘
            excuteReCheck(user.getId(), user.getUsername(), now, row, model);
            Map<String, Object> updateMap = MapUtils.put("pieceQuantityFact", pieceQuantityFact).put("caseQuantityFact", model.getCaseQuantityFact()).put("oddQuantityFact", model.getOddQuantityFact()).put("quantityDiff", pieceQuantityFact.subtract(pieceQuantityAccount)).put("status", "5").put("checkDate", now).getMap();
            invCheckDMapper.updateMapById(model.getCheckLineId(), updateMap, WmsInvCheckD.class);
            WarehouseLocatorBasicInfo locatorBasicInfo = locatorBasicInfos.stream().filter(var -> var.getWarehouseLocatorId().equals(wmsInvCheckD.getWhLocatorId())).findFirst().orElse(null);
            // 盘点无差异的也需要审核，审核通过后才推送盘点审核信息至EIS-2024-03-07
            // 需要判断盘点数量是否一致 一致则直接调用EIS盘点审核接口推送结果
//            if (pieceQuantityAccount.compareTo(pieceQuantityFact) == 0) {
//                if (null != locatorBasicInfo && (locatorBasicInfo.getWarehouseAreaCategory().equals("AGVZ") || locatorBasicInfo.getWarehouseAreaCategory().equals("MJK"))
//                        || locatorBasicInfo.getWarehouseAreaCategory().equals("AGVSP") || locatorBasicInfo.getWarehouseAreaCategory().equals("AGVQX")
//                        || locatorBasicInfo.getWarehouseAreaCategory().equals("AGVL")) {
//                    // 盘点回传EIS
//                    InventoryAuditVO toEis = new InventoryAuditVO();
//                    toEis.setMsgId(IdUtil.fastSimpleUUID());
//                    toEis.setWarehouseId(locatorBasicInfo.getWarehouseId());
//                    toEis.setWorkType(InventoryAuditEnum.INV_ADJUST.getWorkType());
//                    toEis.setBusinessType(InventoryAuditEnum.INV_ADJUST.getBusinessType());
//                    toEis.setOwnerId(wmsInvCheckD.getCargoOwnerId());
//                    toEis.setItemId(wmsInvCheckD.getItemId());
//                    toEis.setLotId(wmsInvCheckD.getBatchId());
//                    toEis.setTaskLineId(wmsInvCheckD.getCheckLineId());
//                    String packId = "";
//                    BaseMtlItemMst itemMst = itemMsg.getData().stream().filter(var -> var.getItemId().equals(wmsInvCheckD.getItemId())).findFirst().orElse(null);
//                    if (null == itemMst) {
//                        throw new ParameterException("根据商品ID【" + wmsInvCheckD.getItemId() + "】没有查询到商品信息！");
//                    }
//                    if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
//                        packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
//                    }
//                    if (StringUtils.isNotEmpty(wmsInvCheckD.getContainerCode()) && !"N/A".equals(wmsInvCheckD.getContainerCode())) {
//                        toEis.setContainerNo(wmsInvCheckD.getContainerCode());
//                    }
//                    if (StringUtils.isNotEmpty(wmsInvCheckD.getGoodsCaseCode()) && !"N/A".equals(wmsInvCheckD.getGoodsCaseCode())) {
//                        toEis.setLocNo(wmsInvCheckD.getGoodsCaseCode());
//                    }
//                    toEis.setPackId(packId);
//                    toEis.setContainerNo(wmsInvCheckD.getContainerCode());
//                    toEis.setWmsLocationCode("MJK".equals(locatorBasicInfo.getWarehouseAreaCode()) ? "MJZ" : locatorBasicInfo.getWarehouseAreaCode());
//                    toEis.setConfirmQty(model.getPieceQuantityFact().toString());
//                    toEisVos.add(toEis);
//                }
//            }
        }
//        if (CollUtil.isNotEmpty(toEisVos)){
//            eisHandler.inventoryAudit(toEisVos);
//        }
    }

    /**
     * 盘点录入保存，生成差异,给盘点单回传定时任务用
     *
     * @param list
     */
    @Transactional
    public void updateInvCheck(List<WmsInvCheckUpdateVO> list, UserDTO userDTO) {
        if (list == null || list.isEmpty()) {
            throw new ParameterException("请选择保存明细！");
        }
        int row = 0;
        Date now = new Date();
        if (userDTO == null) {
            throw new BizException("获取用户信息失败");
        }
        String uid = userDTO.getId();
        String username = userDTO.getUsername();
        for (WmsInvCheckUpdateVO model : list) {
            row++;
            if (model.getCaseQuantityFact() == null || model.getOddQuantityFact() == null) {
                throw new ParameterException(String.format("第[%d]行,操作的数量不可为空!", row));
            }
            // 更新复盘
            try {
                excuteReCheck(uid, username, now, row, model);
            } catch (Exception e) {
                e.printStackTrace();
            }
            BigDecimal pieceQuantityFact = model.getPieceQuantityFact();
            BigDecimal pieceQuantityAccount = model.getPieceQuantityAccount();
            AssertUtils.notNull(pieceQuantityFact, "实际盘点数量不可为空!");
            AssertUtils.notNull(pieceQuantityAccount, "帐存数量不可为空!");
            Map<String, Object> updateMap = MapUtils.put("pieceQuantityFact", pieceQuantityFact).put("caseQuantityFact", model.getCaseQuantityFact()).put("oddQuantityFact", model.getOddQuantityFact()).put("quantityDiff", pieceQuantityFact.subtract(pieceQuantityAccount)).put("status", "5").put("checkDate", now).getMap();
            invCheckDMapper.updateMapById(model.getCheckLineId(), updateMap, WmsInvCheckD.class);
        }

        String[] dIds = list.stream().map(WmsInvCheckUpdateVO::getCheckLineId).distinct().toArray(String[]::new);
        invCheckHMapper.updateCheckDoneStatus(dIds);
    }

    /**
     * 盘点差异审核
     *
     * @param map type:审核类型（15：审核通过转损溢 20：作废）
     */
    @Transactional
    @Override
    @TxTransaction(isStart = true)
    public void examineInvCheck(Map<String, Object> map) {
        String checkLineIds = (String) map.get("checkLineIds");
        String type = (String) map.get("type");
        UserDTO userDTO = userService.getUser();
        excuteUpdateCheckDStatus(checkLineIds, type, userDTO);
        if ("20".equals(type)) {
            // 作废需要推送盘点差异审核结果给EIS
            this.pushAdjustResultToEis(checkLineIds);
            // 作废需要释放生成盘点任务时的盘点预占
            InvStockCancel cancel = new InvStockCancel();
            cancel.setLineBillIds(checkLineIds.split(","));
            stockResource.adjustCancel(cancel);
        }
        // 审核通过，转损溢
        if (type.equals("15")) {
            adjustService.saveBatchAdjust(checkLineIds);
        }
    }

    private void pushAdjustResultToEis(String checkLineIds) {
        if (StringUtils.isEmpty(checkLineIds)) {
            throw new ParameterException("id不能为空！");
        }
        List<WmsInvCheckD> checkDList = invCheckDMapper.findByIds(WmsInvCheckD.class, checkLineIds.split(","), null);
        if (CollUtil.isEmpty(checkDList)) {
            throw new ParameterException("根据盘点明细ID没有查询到盘点明细数据！");
        }

        Set<String> locatorIds = checkDList.stream().map(WmsInvCheckD::getWhLocatorId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        RestMessage<List<WarehouseLocatorBasicInfo>> locatorMsg = warehouseResource.getLocationBasicInfos(locatorIds.toArray(new String[]{}));
        if (!locatorMsg.isSuccess() || CollUtil.isEmpty(locatorMsg.getData())) {
            throw new BizException("查询货位信息失败！");
        }
        List<WarehouseLocatorBasicInfo> locList = locatorMsg.getData();

        Set<String> itemIds = checkDList.stream().map(WmsInvCheckD::getItemId).filter(StrUtil::isNotEmpty).collect(Collectors.toSet());
        RestMessage<List<BaseMtlItemMst>> itemMsg = itemResource.getListByIds(itemIds);
        if (!itemMsg.isSuccess() || CollUtil.isEmpty(itemMsg.getData())) {
            throw new BizException("查询商品信息失败！");
        }
        // 无差异的盘点记录，则调用接口【盘点审核信息推送】同步发送盘点审核指令到EIS
        // 盘点回传EIS
        List<InventoryAuditVO> toEisVos = new ArrayList<>();
        for (WmsInvCheckD wmsInvCheckD : checkDList) {
            WarehouseLocatorBasicInfo locatorInfo = locList.stream().filter(loc -> loc.getWarehouseLocatorId().equals(wmsInvCheckD.getWhLocatorId())).findFirst().orElse(null);
            if (null == locatorInfo) {
                throw new ParameterException("没有查询到货位信息！");
            }
            // 非设备库任务不用推送
            if (!PICK_MODE_DEVICE.equals(locatorInfo.getPickMode())) {
                continue;
            }
            // 拆零区任务不用推送
//            if ("AGVL".equals(locatorInfo.getWarehouseAreaCategory())) {
//                continue;
//            }
            InventoryAuditVO toEisVo = new InventoryAuditVO();
            toEisVo.setMsgId(IdUtil.fastSimpleUUID());
            toEisVo.setWarehouseId(locatorInfo.getWarehouseId());
            toEisVo.setWorkType(InventoryAuditEnum.INV_ADJUST.getWorkType());
            toEisVo.setBusinessType(InventoryAuditEnum.INV_ADJUST.getBusinessType());
            toEisVo.setBillNo(wmsInvCheckD.getCheckHeaderId());
            toEisVo.setTaskLineId(wmsInvCheckD.getCheckLineId());
            toEisVo.setOwnerId(wmsInvCheckD.getCargoOwnerId());
            toEisVo.setItemId(wmsInvCheckD.getItemId());
            toEisVo.setLotId(wmsInvCheckD.getBatchId());
            toEisVo.setWmsLocationCode("MJK".equals(locatorInfo.getWarehouseAreaCode()) ? "MJZ" : locatorInfo.getWarehouseAreaCode());
            toEisVo.setConfirmQty(wmsInvCheckD.getPieceQuantityAccount().toString());
            String packId = "";
            BaseMtlItemMst itemMst = itemMsg.getData().stream().filter(var -> var.getItemId().equals(wmsInvCheckD.getItemId())).findFirst().orElse(null);
            if (null == itemMst) {
                throw new BizException("根据商品ID【" + wmsInvCheckD.getItemId() + "】查询商品信息失败！");
            }
            if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
                packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
            }
            toEisVo.setPackId(packId);
            if (StringUtils.isNotEmpty(wmsInvCheckD.getContainerCode()) && !"N/A".equals(wmsInvCheckD.getContainerCode())) {
                toEisVo.setContainerNo(wmsInvCheckD.getContainerCode());
            }
            if (StringUtils.isNotEmpty(wmsInvCheckD.getGoodsCaseCode()) && !"N/A".equals(wmsInvCheckD.getGoodsCaseCode())) {
                toEisVo.setLocNo(wmsInvCheckD.getGoodsCaseCode());
            }

            toEisVos.add(toEisVo);
        }
        if (CollUtil.isNotEmpty(toEisVos)) {
            eisHandler.inventoryAudit(toEisVos);
        }
    }

    @Override
    public Page<InvCheckListVO> getCheckList(String warehouseId) {
        UserDTO user = userService.getUser();
        Criteria criteria = Criteria.forClass(WmsInvCheckH.class);
        criteria.restrictionBuilder().eq("warehouseId", warehouseId).eq("enterpriseId", user.getEnterpriseId()).in("status", new String[]{"NEW"});
        criteria.buildRestriction();
        // 盘点单列表
        List<WmsInvCheckH> hList = invCheckHMapper.findByCriteria(criteria);
        if (CollectionUtil.isEmpty(hList)) {
            return null;
        }
        // 根据盘点汇总ID查询盘点明细数据
        String[] hIds = hList.stream().map(WmsInvCheckH::getCheckHeaderId).distinct().toArray(String[]::new);
        Criteria param4D = Criteria.forClass(WmsInvCheckD.class);
        param4D.restrictionBuilder().in("checkHeaderId", hIds);
        param4D.buildRestriction();
        List<WmsInvCheckD> dList = invCheckDMapper.findByCriteria(param4D);
        if (CollUtil.isEmpty(dList)) {
            throw new BizException("没有查询到盘点明细数据！");
        }
        // 查询货位信息
        String[] locationIds = dList.stream().map(WmsInvCheckD::getWhLocatorId).distinct().toArray(String[]::new);
        List<WarehouseLocatorBasicInfo> locations = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locationIds));
        if (CollUtil.isEmpty(locations)) {
            throw new BizException("查询货位信息失败！");
        }
        List<WmsInvCheckH> checkHList;
        // 排除掉AGVL-零货库区的盘点任务，零货库区的盘点任务EIS进行盘点
        List<String> agvLocIds = locations.stream().filter(loc -> "AGVL".equals(loc.getWarehouseAreaCategory())).map(WarehouseLocatorBasicInfo::getWarehouseLocatorId).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(agvLocIds)) {
            dList = dList.stream().filter(checkd -> !agvLocIds.contains(checkd.getWhLocatorId())).collect(Collectors.toList());
            // 如果全部是零货库区的盘点任务，则直接返回空
            if (CollUtil.isEmpty(dList)) {
                return null;
            }
            // 过滤盘点汇总数据
            List<String> checkHeaderIds = dList.stream().map(WmsInvCheckD::getCheckHeaderId).distinct().collect(Collectors.toList());
            checkHList = hList.stream().filter(checkh -> checkHeaderIds.contains(checkh.getCheckHeaderId())).collect(Collectors.toList());
        } else {
            checkHList = hList;
        }
        Map<String, List<WmsInvCheckD>> result = dList.stream().collect(Collectors.groupingBy(WmsInvCheckD::getCheckHeaderId));

        // 盘点方式
        String[] checkMethods = checkHList.stream().map(WmsInvCheckH::getCheckMethod).distinct().toArray(String[]::new);
        // 盘点类型
        String[] checkTypes = checkHList.stream().map(WmsInvCheckH::getCheckType).distinct().toArray(String[]::new);
        RestMessage<List<BaseCommonDict>> checkMethodResult = commonResource.getDictBasicListByCodes(CommonResource.typeCode.inv_stockcheck_h_checkgroup2.name(), checkMethods);
        RestMessage<List<BaseCommonDict>> checkTypeResult = commonResource.getDictBasicListByCodes(CommonResource.typeCode.inv_stockcheck_type.name(), checkTypes);

        Page<WmsInvCheckH> page = PageUtils.getPage(checkHList);

        return BeanConvertUtils.convertPageTo(page, InvCheckListVO::new, (s, t) -> {
            if (checkMethodResult.isSuccess() && checkMethodResult.getData() != null) {
                checkMethodResult.getData().stream().filter(x -> x.getDictCode().equals(s.getCheckMethod())).findFirst().ifPresent(commonDict -> t.setCheckMethodName(commonDict.getDictName()));
            }
            if (checkTypeResult.isSuccess() && checkTypeResult.getData() != null) {
                checkTypeResult.getData().stream().filter(x -> x.getDictCode().equals(s.getCheckType())).findFirst().ifPresent(commonDict -> t.setCheckTypeName(commonDict.getDictName()));
            }
            List<WmsInvCheckD> dtls = result.get(t.getCheckHeaderId());
            t.setMolecular(dtls.stream().filter(d -> Integer.parseInt(d.getStatus()) > CheckStatusEnum.NEW.getCode() && Integer.parseInt(d.getStatus()) != CheckStatusEnum.replay.getCode()).count());
            t.setDenominator((long) dtls.size());

            List<String> dtlIds = dtls.stream().filter(d -> isDevice(d.getWhLocatorId(), locations)).map(WmsInvCheckD::getCheckLineId).collect(Collectors.toList());
            t.setDtlIds(dtlIds);
        });
    }

    private boolean isDevice(String locationId, List<WarehouseLocatorBasicInfo> locations) {
        return locations.stream().anyMatch(l -> l.getWarehouseLocatorId().equals(locationId) && PICK_MODE_DEVICE.equals(l.getPickMode()));
    }

    @Override
    public InvCheckDetailPdaVO getCurrentCheckDetail(String checkHeaderId, String warehouseId, String locatorId, String containerCode) {
        UserDTO userDTO = userService.getUser();
        Criteria criteriaH = Criteria.forClass(WmsInvCheckH.class);
        criteriaH.restrictionBuilder().eq("warehouseId", warehouseId).eq("enterpriseId", userDTO.getEnterpriseId()).eq("checkHeaderId", checkHeaderId);
        criteriaH.buildRestriction();
        List<WmsInvCheckH> hList = invCheckHMapper.findByCriteria(criteriaH);
        Assert.notEmpty(hList, "未找到有效的盘点单");

        WmsInvCheckH hInfo = hList.get(0);

        // 根据LineNum排序盘点详情
        Criteria criteria = Criteria.forClass(WmsInvCheckD.class);
        criteria.restrictionBuilder().eq("checkHeaderId", checkHeaderId).ne("status", "2");

        if (StrUtil.isNotBlank(locatorId)) {
            criteria.restrictionBuilder().eq("whLocatorId", locatorId);
        }
        if (StrUtil.isNotBlank(containerCode)) {
            criteria.restrictionBuilder().eq("containerCode", containerCode);
        }
        criteria.setOrder(Order.newInstance().asc("lineNum"));
        criteria.buildRestriction();
        List<WmsInvCheckD> dList = invCheckDMapper.findByCriteria(criteria);
        if (CollUtil.isEmpty(dList)) {
            return null;
        }
        String[] locIds = dList.stream().map(WmsInvCheckD::getWhLocatorId).toArray(String[]::new);
        List<WarehouseLocatorBasicInfo> locatorList = RestMsgHelper.unpack(warehouseClient.getLocationBasicInfos(locIds));
        if (CollUtil.isEmpty(locatorList)) {
            throw new BizException("没有查询到货位信息！");
        }
        List<String> locatorIds = locatorList.stream().filter(loc -> "AGVL".equals(loc.getWarehouseAreaCategory())).map(WarehouseLocatorBasicInfo::getWarehouseLocatorId).collect(Collectors.toList());
        // 查询刚生成和复盘的盘点明细数据
        WmsInvCheckD detail = dList.stream().filter(x -> ("0".equals(x.getStatus()) || "30".equals(x.getStatus())) && !locatorIds.contains(x.getWhLocatorId())).findFirst().orElse(null);
        if (detail == null) {
            return null;
        }

        RestMessage<Map<String, BaseCargoOwnerMst>> cargoResult = chainResource.getCargoOwerByIds(Collections.singleton(hInfo.getCargoOwnerId()));

        // 根据batchId locatorId stockStatus匹配库存
        WmsInvStockQtyQueryVO queryVO = new WmsInvStockQtyQueryVO();
        queryVO.setEnterpriseId(userDTO.getEnterpriseId());
        queryVO.setWarehouseId(hInfo.getWarehouseId());
        queryVO.setCargoOwnerId(hInfo.getCargoOwnerId());
        queryVO.setLocatorId(detail.getWhLocatorId());
        queryVO.setBatchId(detail.getBatchId());
        queryVO.setStatus(detail.getStockStatus());

        RestMessage<List<WmsInvStockQtyVO>> avlQtyList = stockResource.getAvailableQuantity(BeanUtil.beanToMap(queryVO));

        RestMessage<List<BaseCommonDict>> checkMethodResult = commonResource.getDictBasicListByCodes(CommonResource.typeCode.inv_stockcheck_h_checkgroup2.name(), new String[]{hInfo.getCheckMethod()});

        List<ItemBaseInfoVO> items = RestMsgHelper.unpack(itemResource.getItemBaseList(dList.stream().map(WmsInvCheckD::getItemId).distinct().toArray(String[]::new)));

        List<BatchNumberListVO> batchNumbers = RestMsgHelper.unpack(stockResource.getBatchNumberBasicInfo((dList.stream().map(WmsInvCheckD::getBatchId).distinct().toArray(String[]::new))));

        return BeanConvertUtils.convertTo(detail, InvCheckDetailPdaVO::new, (s, t) -> {
            t.setLocatorId(s.getWhLocatorId());
            t.setTotalNum(dList.size());
            if (cargoResult.isSuccess() && MapUtil.isNotEmpty(cargoResult.getData())) {
                BaseCargoOwnerMst cargo = cargoResult.getData().get(hInfo.getCargoOwnerId());
                if (cargo != null) {
                    t.setCargoOwnerName(cargo.getCargoOwnerName());
                }
            }
            if (avlQtyList.isSuccess() && avlQtyList.getData() != null && !avlQtyList.getData().isEmpty()) {
                WmsInvStockQtyVO stockQty = avlQtyList.getData().get(0);
                if (stockQty != null) {
                    t.setQuantity(stockQty.getQuantity());
                    t.setManufacturerLotNum(stockQty.getManufacturerLotNum());
                    t.setBatchProductionDate(stockQty.getBatchProductionDate());
                    t.setBatchExpiredDate(stockQty.getBatchExpiredDate());
                    t.setBatchProductionDateShow(stockQty.getBatchProductionDateShow());
                    t.setBatchExpiredDateShow(stockQty.getBatchExpiredDateShow());
                    t.setLocatorCode(stockQty.getLocatorCode());

                    t.setItemName(stockQty.getItemName());
                    t.setCaseUom(stockQty.getCaseUom());
                    t.setSpecification(stockQty.getSpecification());
                    t.setCaseConvertionRate(stockQty.getCaseConversionRate());
                }
            }

            if (checkMethodResult.isSuccess() && CollectionUtil.isNotEmpty(checkMethodResult.getData())) {
                t.setCheckMethod(checkMethodResult.getData().get(0).getDictCode());
                t.setCheckMethodName(checkMethodResult.getData().get(0).getDictName());
            }

            WarehouseLocatorBasicInfo locatorBasicInfo = locatorList.stream().filter(loc -> detail.getWhLocatorId().equals(loc.getWarehouseLocatorId())).findFirst().orElse(null);
            if (null != locatorBasicInfo) {
                t.setWarehouseAreaCategory(locatorBasicInfo.getWarehouseAreaCategory());
            }
            if (CollUtil.isNotEmpty(items)) {
                items.stream().filter(i -> i.getItemId().equals(t.getItemId())).findFirst().ifPresent(i -> {
                    t.setItemName(i.getItemName());
                    t.setCaseUom(i.getCaseUom());
                    t.setSpecification(i.getSpecification());
                    t.setCaseConvertionRate(i.getCaseConversionRate());
                });
            }
            if (CollUtil.isNotEmpty(batchNumbers)) {
                batchNumbers.stream().filter(b -> b.getBatchId().equals(t.getBatchId())).findFirst().ifPresent(b -> {
                    t.setBatchExpiredDate(b.getBatchExpiredDate());
                    t.setBatchExpiredDateShow(b.getBatchExpiredDateShow());
                    t.setBatchProductionDate(b.getBatchProductionDate());
                    t.setBatchProductionDateShow(b.getBatchProductionDateShow());
                });
            }
            t.setQuantity(s.getPieceQuantityAccount());
        });
    }

    private void excuteUpdateCheckDStatus(String checkLineIds, String type, UserDTO userDTO) {
        if (StringUtils.isEmpty(checkLineIds))
            throw new ParameterException("id不能为空！");
        if (StringUtils.isEmpty(type))
            throw new ParameterException("审核类型不能为空！");
        Date date = new Date();
        if (userDTO == null) {
            throw new BizException("无用户信息,请刷新重试,或重新登录!");
        }
        String userId = userDTO.getId();
        String userName = userDTO.getNickname();
        for (String checkLineId : checkLineIds.split(",")) {
            invCheckDMapper.updateMapById(checkLineId, MapUtils.put("status", type).put("gmtModified", date).put("modifier", userId).put("modifierName", userName).put("outboundInstruct", null).getMap(), WmsInvCheckD.class);
        }

    }

    /**
     * 生成复盘
     */
    @Override
    @Transactional
    public void addInvCheckRe(Map<String, Object> map) {
        AssertUtils.isNotNull(map, "操作的数据为空!");
        // Step1: 查询盘点表看是否已复盘,没复盘更改状态为已复盘,并记录复盘的次数,并更改审核的状态
        String checkLineIds = (String) map.get("checkLineIds");
        String type = "30"; // 复盘
        UserDTO userDTO = userService.getUser();
        excuteUpdateCheckDStatus(checkLineIds, type, userDTO);
        // Step2: 判断是否新增复盘记录,生成初盘的记录
        String[] split = checkLineIds.split(",");

        // 更新汇总状态为NEW
        invCheckHMapper.updateCheckNewStatus(split);
        for (String checkLineId : split) {
            WmsInvCheckDRe checkDRe = invCheckDReMapper.findById(checkLineId, WmsInvCheckDRe.class);
            if (checkDRe == null) {
                // 需新增新的复盘记录
                WmsInvCheckD checkD = invCheckDMapper.findById(checkLineId, WmsInvCheckD.class);
                checkDRe = new WmsInvCheckDRe();
                BeanUtils.copyProperties(checkD, checkDRe);
                checkDRe.setPieceQuantityFact(checkD.getPieceQuantityFact());
                ModelUtils.setBaseInfo(checkDRe, OpType.INSERT, userDTO);
                checkDRe.setCheckTimes(0);
                invCheckDReMapper.save(checkDRe);
            }
        }
        // 个人觉得此处应该考虑并发情况,多个人同时点了复盘
//        List<WmsInvCheckD> checkDList = invCheckDMapper.findByIds(WmsInvCheckD.class, split, null);
//        // 封装出库任务推送参数推送出库任务至EIS
//        String[] locationIds = checkDList.stream().map(WmsInvCheckD::getWhLocatorId).distinct().toArray(String[]::new);
//        List<WarehouseLocatorBasicInfo> locations = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locationIds));
//        List<WarehouseLocatorBasicInfo> stereoLocations = locations.stream().filter(l -> PICK_MODE_DEVICE.equals(l.getPickMode())).collect(Collectors.toList());
//        if (CollUtil.isEmpty(stereoLocations)) {
//            return;
//        }
//        List<String> stereoLocationIds = stereoLocations.stream().map(WarehouseLocatorBasicInfo::getWarehouseLocatorId).collect(Collectors.toList());
//        List<WmsInvCheckD> stereoCheckds = checkDList.stream().filter(d -> stereoLocationIds.contains(d.getWhLocatorId())).collect(Collectors.toList());
//        if (CollUtil.isEmpty(stereoCheckds)) {
//            return;
//        }
//        List<BaseMtlItemMst> items = RestMsgHelper.unpack(itemResource.getListByIds(stereoCheckds.stream().map(WmsInvCheckD::getItemId).collect(Collectors.toSet())));
//        Assert.notEmpty(items, "没有查询到商品信息！");
//        // 封装正确的EIS出库请求参数
//        Map<String, List<WmsInvCheckD>> checkMap = stereoCheckds.stream().collect(Collectors.groupingBy(WmsInvCheckD::getCheckHeaderId));
//
//        // 根据盘点汇总ID查询盘点汇总信息
//        Object[] checkHeaderIds = stereoCheckds.stream().map(WmsInvCheckD::getCheckHeaderId).distinct().toArray();
//        List<WmsInvCheckH> checkHList = invCheckHMapper.findByIds(WmsInvCheckH.class, checkHeaderIds, null);
//        Assert.notEmpty(checkHList, "没有查询到盘点汇总信息！");
//
//        List<OutBoundRequestVO> paramList = new ArrayList<>();
//        for (Map.Entry<String, List<WmsInvCheckD>> checkEntry : checkMap.entrySet()) {
//            List<WmsInvCheckD> invCheckList = checkEntry.getValue();
//            WmsInvCheckH wmsInvCheckH = checkHList.stream().filter(checkH -> checkEntry.getKey().equals(checkH.getCheckHeaderId())).findFirst().orElse(null);
//            if (null == wmsInvCheckH) {
//                throw new PrologException(String.format("根据盘点汇总ID【%s】没有查询到盘点汇总信息！", checkEntry.getKey()));
//            }
//            // 构建推送EIS入参
//            OutBoundRequestVO requestVO = this.buildPushCheckTaskToEisVo(invCheckList, stereoLocations, items, wmsInvCheckH.getCheckMethod());
//            paramList.add(requestVO);
//        }
//        eisHandler.outBoundRequest(paramList);
//
//        for (WmsInvCheckD checkD : checkDList) {
//            // 设置发送托盘出库指定为已发送未送达-1
//            checkD.setOutboundInstruct(1);
//            invCheckDMapper.update(checkD);
//        }
    }

    /**
     * 盘点单回传
     */
    @Override
    @Transactional
    public Object countSheetReceive(Map<String, Object> map) {
        // 查询AGV盘点接口表，生成盘点任务单，生成差异及审核结果
        // 接收移库入任务回传
        IntegrationSearchData sd = new IntegrationSearchData();
        // 正方体agv-盘点单回传查询 336
        sd.setInterfaceId(countSheetId);
        // Map<String, Object> data2 = MapUtils.put("type", 1).getMap();
        // sd.setData(data2);
        List<Map> mapList = null;
        try {
            String string = JsonUtils.toString(sd);
            logger.info("索取盘点单回传请求参数->" + string);
            mapList = integrationApi.searchForRestMessageMap(sd);
        } catch (Exception e) {
            logger.error("索取盘点单回传,调用接口平台失败,原因->{}", e.getMessage());
            throw new BizException("索取盘点单回传,调用接口平台失败,原因->" + e.getMessage());
        }
        if (ObjectUtils.isEmpty(mapList)) {
            throw new BizException("索取盘点单回传的数据为空!请重试!");
        }
        if (CollectionUtil.isNotEmpty(mapList)) {
            // 执行生成差异及审核结果
            // 盘点录入保存，生成差异
            List<WmsInvCheckUpdateVO> checkUpdateList = new ArrayList<>();
            WmsInvCheckUpdateVO wmsInvCheckUpdateVO = null;
            String enterpriseId = "";
            String userId = "";
            String userName = "";
            for (Map returnMap : mapList) {
                // 根据taskId查询计划明细行
                String checkLineId = String.valueOf(returnMap.get("TASK_ID"));
                WmsInvCheckD checkD = invCheckDMapper.findById(checkLineId, WmsInvCheckD.class);
                AssertUtils.notNull(checkD, "查询的第一条明细数据为空!请检查重试!");
                enterpriseId = checkD.getEnterpriseId();
                userId = checkD.getModifier();
                userName = checkD.getModifierName();
                wmsInvCheckUpdateVO = new WmsInvCheckUpdateVO();
                BeanUtils.copyProperties(checkD, wmsInvCheckUpdateVO);
                wmsInvCheckUpdateVO.setCheckLineId(String.valueOf(returnMap.get("TASK_ID")));
                wmsInvCheckUpdateVO.setWarehouseId(String.valueOf(returnMap.get("WAREHOUSE_CODE")));
                wmsInvCheckUpdateVO.setPieceQuantityFact(new BigDecimal(String.valueOf(returnMap.get("AMOUNT"))));
                checkUpdateList.add(wmsInvCheckUpdateVO);
            }
            // 盘点录入保存，生成差异
            // 生成userDTO
            UserDTO user = new UserDTO();
            user.setEnterpriseId(enterpriseId);
            user.setId(userId);
            user.setUsername(userName);
            user.setNickname(userName);
            updateInvCheck(checkUpdateList, user);
            // 然后报损溢
            String checkLineIds = getCheckLineIds(checkUpdateList);
            String type = "15";
            excuteUpdateCheckDStatus(checkLineIds, type, user);
            // 审核通过，转损溢
            adjustService.saveBatchAdjust(checkLineIds);
            // 更新回传状态
            Set<String> collect = mapList.stream().filter(p -> !StringUtils.isEmpty((String) p.get("TASK_ID"))).map(p -> (String) p.get("TASK_ID")).collect(Collectors.toSet());
            IntegrationSearchData sd2 = new IntegrationSearchData();
            for (String string : collect) {
                sd2.setInterfaceId(countSheetOutId);
                List<Map<String, Object>> paraListMap = new ArrayList<>();
                Map<String, Object> map2 = MapUtils.put("task_id", string).put("status", 1).getMap();
                paraListMap.add(map2);
                Map<String, Object> params = MapUtils.put("param", paraListMap).getMap();
                sd2.setData(params);
                try {
                    logger.info("盘点单任务id->" + string + ",更新盘点单状态入参->" + JsonUtils.toString(sd2));
                    String searchForJsonStr = integrationApi.searchForJsonStr(sd2);
                    searchForJsonStr = StringUtils.replaceBlank(searchForJsonStr);
                    JsonNode parse = JsonUtils.parse(searchForJsonStr);
                    boolean has = parse.has("success");
                    if (has) {
                        boolean asBoolean = parse.get("success").asBoolean();
                        if (!asBoolean) {
                            logger.info("盘点单任务id->" + string + ",更新盘点单状态入参失败->" + JsonUtils.toString(sd2));
                            throw new BizException("盘点单任务id->" + string + ",更新盘点单状态入参失败->" + JsonUtils.toString(sd2));
                        }
                    }
                } catch (Exception e) {
                    logger.error("盘点单任务id->" + string + ",更新盘点单状态失败,原因->" + e.getMessage());
                    throw new BizException("盘点单任务id->" + string + ",更新盘点单状态失败,原因->" + e.getMessage());
                }
            }
        }
        return null;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void sendDeviceOrder4Check(List<String> list) {

        List<WmsInvCheckD> checkDS = invCheckDMapper.findByIds(WmsInvCheckD.class, list.toArray(), null);
        Assert.notEmpty(checkDS, "盘点单明细不存在");

        String[] locationIds = checkDS.stream().map(WmsInvCheckD::getWhLocatorId).distinct().toArray(String[]::new);
        List<WarehouseLocatorBasicInfo> locations = RestMsgHelper.unpack(warehouseResource.getLocationBasicInfos(locationIds));
        Assert.notEmpty(locations, "没有查询到货位信息！");
        List<WarehouseLocatorBasicInfo> stereoLocations = locations.stream().filter(l -> PICK_MODE_DEVICE.equals(l.getPickMode())).collect(Collectors.toList());
        Assert.notEmpty(stereoLocations, "勾选的盘点记录中没有需要发送设备指令的记录");

        List<String> stereoLocationIds = stereoLocations.stream().map(WarehouseLocatorBasicInfo::getWarehouseLocatorId).collect(Collectors.toList());
        List<WmsInvCheckD> stereoCheckds = checkDS.stream().filter(d -> stereoLocationIds.contains(d.getWhLocatorId())).collect(Collectors.toList());
        Assert.notEmpty(stereoCheckds, "勾选的盘点记录中没有需要发送设备指令的记录");

        WmsInvCheckD sendOrder = stereoCheckds.stream().filter(d -> d.getOutboundInstruct() != null && !OUTBOUND_INSTRUCT_NO_SEND.equals(d.getOutboundInstruct())).findFirst().orElse(null);
        if (sendOrder != null) {
            BaseMtlItemMst itemMst = RestMsgHelper.unpack(itemResource.item(sendOrder.getItemId()));
            throw new PrologException(String.format("商品编码【%s】已发送指令，不能重复发送", itemMst.getItemCode()));
        }

        DateTime now = DateUtil.date();
        stereoCheckds.forEach(d -> {
            d.setOutboundInstruct(OUTBOUND_INSTRUCT_UN_DELIVERY);
            d.setGmtModified(now);
            invCheckDMapper.update(d);
        });
        // 封装正确的EIS出库请求参数
        Map<String, List<WmsInvCheckD>> checkMap = stereoCheckds.stream().collect(Collectors.groupingBy(WmsInvCheckD::getCheckHeaderId));

        // 根据盘点汇总ID查询盘点汇总信息
        Object[] checkHeaderIds = stereoCheckds.stream().map(WmsInvCheckD::getCheckHeaderId).distinct().toArray();
        List<WmsInvCheckH> checkHList = invCheckHMapper.findByIds(WmsInvCheckH.class, checkHeaderIds, null);
        Assert.notEmpty(checkHList, "没有查询到盘点汇总信息！");

        List<BaseMtlItemMst> items = RestMsgHelper.unpack(itemResource.getListByIds(stereoCheckds.stream().map(WmsInvCheckD::getItemId).collect(Collectors.toSet())));
        Assert.notEmpty(items, "没有查询到商品信息！");
        List<OutBoundRequestVO> paramList = new ArrayList<>();
        for (Map.Entry<String, List<WmsInvCheckD>> checkEntry : checkMap.entrySet()) {
            List<WmsInvCheckD> checkDList = checkEntry.getValue();
            WmsInvCheckH wmsInvCheckH = checkHList.stream().filter(checkH -> checkEntry.getKey().equals(checkH.getCheckHeaderId())).findFirst().orElse(null);
            if (null == wmsInvCheckH) {
                throw new PrologException(String.format("根据盘点汇总ID【%s】没有查询到盘点汇总信息！", checkEntry.getKey()));
            }
            // 构建推送EIS入参
            OutBoundRequestVO requestVO = this.buildPushCheckTaskToEisVo(checkDList, stereoLocations, items, wmsInvCheckH.getCheckMethod());
            paramList.add(requestVO);
        }
        eisHandler.outBoundRequest(paramList);
    }

    private OutBoundRequestVO buildPushCheckTaskToEisVo(List<WmsInvCheckD> dInfoList, List<WarehouseLocatorBasicInfo> stereoLocations,
                                                        List<BaseMtlItemMst> items, String checkType) {
        OutBoundRequestVO requestVO = new OutBoundRequestVO();
        requestVO.setMsgId(IdUtil.fastSimpleUUID());
        requestVO.setWarehouseId(stereoLocations.get(0).getWarehouseId());
        requestVO.setGroupOrderPolicy("4");
        List<OutBoundRequestItemVO> subList = new ArrayList<>();
        for (WmsInvCheckD dInfo : dInfoList) {
            BaseMtlItemMst itemMst = items.stream().filter(var -> dInfo.getItemId().equals(var.getItemId())).findFirst().orElse(null);
            if (null == itemMst) {
                throw new PrologException(String.format("根据商品ID【%s】没有查询到商品信息！", dInfo.getItemId()));
            }
            WarehouseLocatorBasicInfo locator = stereoLocations.stream().filter(var -> var.getWarehouseLocatorId().equals(dInfo.getWhLocatorId())).findFirst().orElse(null);
            if (null == locator) {
                throw new PrologException(String.format("根据货位ID【%s】没有查询到货位信息！", dInfo.getWhLocatorId()));
            }

            OutBoundRequestItemVO itemVO = new OutBoundRequestItemVO();
            itemVO.setWorkType(OutBoundRequestEnum.INV_PLANCHECK.getWorkType());
            itemVO.setBusinessType(OutBoundRequestEnum.INV_PLANCHECK.getBusinessType());
            itemVO.setTaskId(dInfo.getCheckHeaderId());
            itemVO.setBillNo(dInfo.getCheckHeaderId());
            if (locator.getWarehouseAreaCode().contains("AGVL")) {
                // 拆零区不用传托盘，根据物料、批次、包装盘点
                itemVO.setItemId(itemMst.getItemId());
                String packId = "";
                if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
                    packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
                }
                itemVO.setPackId(packId);
                itemVO.setLotId(dInfo.getBatchId());
            } else {
                // 非拆零区需要传托盘号
                itemVO.setContainerNo(dInfo.getContainerCode());
            }
            itemVO.setTaskLineId(dInfo.getCheckLineId());
            itemVO.setPriority(10D);
            itemVO.setOwnerId(dInfo.getCargoOwnerId());
            itemVO.setEnterpriseId(dInfo.getEnterpriseId());
            itemVO.setWmsLocationCode("MJK".equals(locator.getWarehouseAreaCode()) ? "MJZ" : locator.getWarehouseAreaCode());
            itemVO.setIsOver("0");
            itemVO.setIsCheck("1");
            itemVO.setCheckType("0".equals(checkType) ? "1" : "2");
            subList.add(itemVO);
        }
        requestVO.setSubList(subList);
        return requestVO;
    }

    @Override
    public void invCheckOutBack(InfTaskOutBackDTO vo) {
        WmsInvCheckD byId = invCheckDMapper.findById(vo.getSeqNo(), WmsInvCheckD.class);
        //四向/盘点回传   //更新盘点单状态为激活状态
        byId.setOutboundInstruct(OUTBOUND_INSTRUCT_DELIVERY);
        byId.setGmtModified(new Date());
        invCheckDMapper.update(byId);
    }

    private EisPushTaskVO convert(WmsInvCheckD dInfo, List<BaseMtlItemMst> items, List<WarehouseLocatorBasicInfo> stereoLocations) {
        BaseMtlItemMst itemMst = items.stream().filter(var -> dInfo.getItemId().equals(var.getItemId())).findFirst().orElse(null);
        WarehouseLocatorBasicInfo locator = stereoLocations.stream().filter(var -> var.getWarehouseLocatorId().equals(dInfo.getWhLocatorId())).findFirst().orElse(null);
        EisPushTaskVO vo = new EisPushTaskVO();
        vo.setMsgId(cn.hutool.core.util.IdUtil.fastSimpleUUID());
        vo.setTaskId(dInfo.getCheckLineId());
        vo.setWarehouseId("JXYJ");
        vo.setWorkType("30");
        vo.setBusinessType("30");
        vo.setPriority(10);
        vo.setSeqNo(dInfo.getCheckLineId());
        vo.setOwnerId(dInfo.getCargoOwnerId());
        vo.setItemId(dInfo.getItemId());
        vo.setLotId(dInfo.getBatchId());
        vo.setQty(dInfo.getPieceQuantityAccount());
        String packId = "";
        vo.setContainerNo(StrUtil.isNotEmpty(dInfo.getContainerCode()) && dInfo.getContainerCode().equals("N/A") ? null : dInfo.getContainerCode());
        if (CollUtil.isNotEmpty(itemMst.getBaseMtlItemUomConversionsList())) {
            packId = itemMst.getBaseMtlItemUomConversionsList().get(0).getItemUomId();
        }
        vo.setPackId(packId);
        vo.setOriginalArea("");
        vo.setOriginalLocation("");
        vo.setTargetLocation("");
        vo.setWmslocationCode(locator.getWarehouseLocatorCode());
        return vo;
    }

    /**
     * 更新复盘数据
     *
     * @param uid
     * @param username
     * @param now
     * @param row
     * @param model
     */
    private void excuteReCheck(String uid, String username, Date now, int row, WmsInvCheckUpdateVO model) {
        // 需要判断数据来源是否是复盘,并判断次数
        String checkLineId = model.getCheckLineId();
        WmsInvCheckD CheckD = invCheckDMapper.findById(checkLineId, WmsInvCheckD.class);
        if (ObjectUtils.isNull(CheckD)) {
            throw new ParameterException(String.format("第[%d]行,查询的盘点记录为空!", row));
        }
        BigDecimal pieceQuantityFact = model.getPieceQuantityFact();
        String remark = model.getRemark();
        String status = CheckD.getStatus();
        if ("30".equals(status.trim())) {
            WmsInvCheckDRe checkDRe = invCheckDReMapper.findById(checkLineId, WmsInvCheckDRe.class);
            if (ObjectUtils.isNotNull(checkDRe)) {
                // 更新对应的复盘记录数据
                Integer checkTimes = checkDRe.getCheckTimes();
                if (checkTimes == null) {
                    checkTimes = 0;
                }
                checkTimes++;
                Map<String, Object> map = MapUtils.put("checkTimes", checkTimes).put("modifier", uid).put("modifierName", username).put("gmtModified", now).getMap();
                if (checkTimes == 1) {
                    // 一次复盘
                    map.put("pieceQuantityFact1", pieceQuantityFact);
                    map.put("operBy1", username);
                    map.put("checkReDate1", now);
                    map.put("remark1", remark);
                } else if (checkTimes == 2) {
                    // 二次复盘
                    map.put("pieceQuantityFact2", pieceQuantityFact);
                    map.put("operBy2", username);
                    map.put("checkReDate2", now);
                    map.put("remark2", remark);
                } else if (checkTimes >= 3) {
                    // 三次复盘及以上
                    map.put("pieceQuantityFact3", pieceQuantityFact);
                    map.put("operBy3", username);
                    map.put("checkReDate3", now);
                    map.put("remark3", remark);
                }
                invCheckDReMapper.updateMapById(checkLineId, map, WmsInvCheckDRe.class);
            }
        }

    }

    /**
     * 封装盘点库下发VO
     *
     * @param locationBasicInfos locationBasicInfos
     * @param invCheckAddVO      invCheckAddVO
     * @param taskList           taskList
     * @return InventoryCheckVO InventoryCheckVO
     * @author lihao
     * @since 2021-11-15
     */
    private List<Map<String, Object>> getIssueDataList(RestMessage<List<WarehouseLocatorBasicInfo>> locationBasicInfos, WmsInvCheckAddVO invCheckAddVO, List<WmsInvCheckD> taskList) {
        List<Map<String, Object>> inventoryList = new ArrayList<>();
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        if (CollectionUtil.isNotEmpty(locationBasicInfos.getData())) {
            List<WarehouseLocatorBasicInfo> list = locationBasicInfos.getData();
            int count = 0;
            for (WarehouseLocatorBasicInfo info : list) {
                if (ObjectUtils.isNotEmpty(info.getPickMode()) && info.getPickMode().equals("Device")) {
                    for (WmsInvCheckD wmsInvCheckD : taskList) {
                        if (wmsInvCheckD.getWhLocatorId().equals(info.getWarehouseLocatorId())) {
                            count++;
                            Map<String, Object> map = new HashMap<>();
                            map.put("id", wmsInvCheckD.getCheckLineId() == null ? count : wmsInvCheckD.getCheckLineId());
                            map.put("djbh", wmsInvCheckD.getCheckHeaderId() == null ? count : wmsInvCheckD.getCheckHeaderId());
                            map.put("rq", df.format(new Date()));
                            map.put("pdfs", invCheckAddVO.getCheckMethod());
                            map.put("pdlx", invCheckAddVO.getCheckType());
                            map.put("djSort", count);
                            map.put("spid", wmsInvCheckD.getItemId() == null ? count : wmsInvCheckD.getItemId());
                            map.put("ph", wmsInvCheckD.getManufacturerLotNum() == null ? count : wmsInvCheckD.getManufacturerLotNum());
                            map.put("sl", wmsInvCheckD.getPieceQuantityAccount() == null ? count : wmsInvCheckD.getPieceQuantityAccount());
                            map.put("kczt", wmsInvCheckD.getStockStatus() == null ? count : wmsInvCheckD.getStockStatus());
                            map.put("yzid", wmsInvCheckD.getCargoOwnerId() == null ? count : wmsInvCheckD.getCargoOwnerId());
                            map.put("taskId", wmsInvCheckD.getCheckLineId() == null ? count : wmsInvCheckD.getCheckLineId());
                            inventoryList.add(map);
                        }
                    }
                }
            }
        }
        return inventoryList;
    }

    /**
     * 拼接ID
     *
     * @param checkUpdateList checkUpdateList
     * @return String String
     * @author lihao
     * @since 2021-11-25
     */
    private String getCheckLineIds(List<WmsInvCheckUpdateVO> checkUpdateList) {
        StringBuffer sb = new StringBuffer();
        for (WmsInvCheckUpdateVO wmsInvCheckUpdateVO : checkUpdateList) {
            sb.append(wmsInvCheckUpdateVO.getCheckLineId());
            sb.append(",");
        }
        String checkLineIds = sb.toString();
        return checkLineIds.substring(0, checkLineIds.length() - 1);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void eisBackUpdateCheckD(List<CompleteTaskVO> backList) {
        if (CollUtil.isEmpty(backList)) {
            return;
        }
        Map<String, List<CompleteTaskItemVO>> backMap = new HashMap<>();
        for (CompleteTaskVO taskVO : backList) {
            if (null == taskVO || ObjectUtils.isNull(taskVO.getTaskLineId())) {
                continue;
            }
            // AGV零货区是EIS盘点结束回告结果
            if (!taskVO.getWmsLocationCode().contains("AGVL")) {
                continue;
            }
            List<CompleteTaskItemVO> itemList = taskVO.getItemList();
            if (CollUtil.isEmpty(itemList)) {
                throw new ParameterException("盘点明细数据不能为空！");
            }
            long emptyCnt = itemList.stream().filter(item -> StringUtils.isEmpty(item.getLocationNo())
                    || null == item.getInventoryQty() || null == item.getConfirmQty()).count();
            if (emptyCnt > 0) {
                throw new ParameterException("盘点明细中货格号、库存数量、实盘数量都不能为空！");
            }

            String taskLineId = taskVO.getTaskLineId();
            WmsInvCheckD checkD = invCheckDMapper.findById(taskLineId, WmsInvCheckD.class);
            if (ObjectUtils.isNull(checkD)) {
                throw new ParameterException("根据盘点明细ID没有查询出盘点明细数据！");
            }
            BigDecimal conversionRate = checkD.getConversionRate();
            Double countQty = itemList.stream().mapToDouble(CompleteTaskItemVO::getConfirmQty).sum();
            BigDecimal pieceQuantityFact = new BigDecimal(countQty.toString());
            if (ObjectUtils.isNotNull(taskVO.getContainerNo())) {
                // 设置容器号
                checkD.setContainerCode(taskVO.getContainerNo());
            }
            // 实盘数量
            checkD.setPieceQuantityFact(pieceQuantityFact);
            // 实盘件数
            checkD.setCaseQuantityFact(pieceQuantityFact.divide(conversionRate, 0, RoundingMode.DOWN));
            // 实盘零散数
            checkD.setOddQuantityFact(pieceQuantityFact.remainder(conversionRate));
            // 差异数量
            checkD.setQuantityDiff(pieceQuantityFact.subtract(checkD.getPieceQuantityAccount()));
            // 设置标识为已收到EIS回告
            checkD.setOutboundInstruct(OUTBOUND_INSTRUCT_DELIVERY);
            // 盘点单直接转损益
            checkD.setStatus("15");
            DateTime now = DateUtil.date();
            checkD.setCheckDate(now);
            checkD.setGmtModified(now);
            String user = StringUtils.isNotEmpty(taskVO.getEmployeeId()) ? taskVO.getEmployeeId() : "EIS";
            checkD.setModifier(user);
            checkD.setModifierName(user);
            invCheckDMapper.update(checkD);

            // 库存数量和实盘数量一致的也生成库存调整单
//            itemList = itemList.stream().filter(item -> item.getInventoryQty().compareTo(item.getConfirmQty()) != 0).collect(Collectors.toList());
            backMap.put(taskVO.getTaskLineId(), itemList);
        }
        // 更新盘点单汇总状态
        String[] checkLineIds = backList.stream().filter(check -> check.getWmsLocationCode().contains("AGVL") && ObjectUtils.isNotNull(check.getTaskLineId()))
                .map(CompleteTaskVO::getTaskLineId).toArray(String[]::new);
        if (ObjectUtils.isNotNull(checkLineIds)) {
            invCheckHMapper.updateCheckDoneStatus(checkLineIds);
        }

        // 生成库存调整单
        if (!backMap.isEmpty()) {
            adjustService.buildAndSaveAdjust(backMap);
        }
    }

    @Override
    public void updateStatus4CheckByEis(OutboundTaskCallbackVO vo) {
        FieldSelector fs = FieldSelector.newInstance().include("checkLineId", "gmtModified", "containerCode", "outboundInstruct");
        String[] lineIds = vo.getSubList().stream().map(OutboundTaskCallbackItemVO::getTaskLineId).toArray(String[]::new);
        List<WmsInvCheckD> list = invCheckDMapper.findByIds(WmsInvCheckD.class, lineIds, fs);
        if (CollUtil.isEmpty(list)) {
            return;
        }

        String containerNo = vo.getContainerNo();

        DateTime now = DateUtil.date();
        TransactionHelper.persistenceErrorThrow(() -> {
            list.forEach(d -> {
                d.setGmtModified(now);
                d.setContainerCode(containerNo);
                d.setOutboundInstruct(OUTBOUND_INSTRUCT_DELIVERY);
                invCheckDMapper.updateFields(d, fs);
            });
        });
    }
}
