package com.prolog.cs.biz.inbound.service.impl.failure;

import com.alibaba.fastjson.JSON;
import com.codingapi.tx.annotation.TxTransaction;
import com.prolog.cs.biz.inbound.constant.BizConstant;
import com.prolog.cs.biz.inbound.constant.OperationConstant;
import com.prolog.cs.biz.inbound.dao.*;
import com.prolog.cs.biz.inbound.dao.failure.ExceptionLinesMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvHeadersMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvInstockLinesMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesMapper;
import com.prolog.cs.biz.inbound.dao.rqc.RqcHeadersMapper;
import com.prolog.cs.biz.inbound.dao.rqc.RqcLinesMapper;
import com.prolog.cs.biz.inbound.dao.rqc.RqcReLinesMapper;
import com.prolog.cs.biz.inbound.dao.rqc.WmsInRqcSampleMapper;
import com.prolog.cs.biz.inbound.dao.task.*;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.failure.ExceptionLineQueryDTO;
import com.prolog.cs.biz.inbound.dto.failure.ExceptionLineQueryVO;
import com.prolog.cs.biz.inbound.dto.failure.ExceptionLinesDTO;
import com.prolog.cs.biz.inbound.model.IncomingRecordD;
import com.prolog.cs.biz.inbound.model.IncomingRecordH;
import com.prolog.cs.biz.inbound.model.ReceivingRecordBackD;
import com.prolog.cs.biz.inbound.model.ReceivingRecordBackH;
import com.prolog.cs.biz.inbound.model.failure.ExceptionLines;
import com.prolog.cs.biz.inbound.model.rcv.RcvInstockLines;
import com.prolog.cs.biz.inbound.model.rcv.RcvLines;
import com.prolog.cs.biz.inbound.model.rqc.RqcHeaders;
import com.prolog.cs.biz.inbound.model.rqc.RqcLines;
import com.prolog.cs.biz.inbound.model.rqc.RqcReLines;
import com.prolog.cs.biz.inbound.model.rqc.WmsInRqcSample;
import com.prolog.cs.biz.inbound.model.task.*;
import com.prolog.cs.biz.inbound.remote.BaseInventoryRemoteCaller;
import com.prolog.cs.biz.inbound.service.OrderInboundStatusBackService;
import com.prolog.cs.biz.inbound.service.failure.ExceptionLinesService;
import com.prolog.cs.biz.inbound.service.failure.ExceptionLogService;
import com.prolog.cs.biz.inbound.service.impl.BaseServiceImpl;
import com.prolog.cs.biz.inbound.service.rcv.RcvInstockLinesService;
import com.prolog.cs.biz.inbound.service.rcv.RcvLinesService;
import com.prolog.cs.biz.inbound.utils.ObjectUtils;
import com.prolog.cs.biz.inbound.utils.UserUtils;
import com.prolog.cs.biz.inbound.vo.*;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.core.collection.ValidList;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.DateUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import com.prolog.upcloud.base.inventory.model.WmsInvBatchNumbers;
import com.prolog.upcloud.base.inventory.vo.*;
import org.apache.commons.collections4.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

@Service
public class ExceptionLinesServiceImpl extends BaseServiceImpl<ExceptionLines> implements ExceptionLinesService {

    @Resource
    private ExceptionLinesMapper mapper;

    @Resource
    private UserUtils userUtils;

    @Resource
    private TaskExceptionDetailMapper taskMapper;

    @Resource
    private RcvHeadersMapper rcvHeadersMapper;

    @Resource
    private RqcHeadersMapper rqcHeadersMapper;

    @Resource
    private ExceptionLogService exceptionLogService;

    @Resource
    private TaskQcDetailMapper taskQcDetailMapper;

    @Resource
    private TaskQcRecheckDetailMapper taskQcRecheckDetailMapper;

    @Resource
    private TaskInstockDetailMapper taskInstockDetailMapper;

    @Resource
    private RqcLinesMapper rqcLinesMapper;

    @Resource
    private RqcReLinesMapper rqcReLinesMapper;

    @Resource
    private WmsInRqcSampleMapper rqcSampleMapper;

    @Resource
    private RcvLinesMapper rcvLinesMapper;

    @Resource
    private RcvLinesService rcvLinesService;

    @Resource
    private RcvInstockLinesMapper instockMapper;

    @Resource
    @Lazy
    private RcvInstockLinesService instockService;

    @Resource
    private TaskRejectedDetailMapper taskRejectedDetailMapper;

    @Resource
    private Validator validator;

    @Resource
    private BaseInventoryRemoteCaller baseInventoryRemoteCaller;

    @Resource
    private IncomingRecordHMapper incomingRecordHMapper;

    @Resource
    private IncomingRecordDMapper incomingRecordDMapper;

    @Resource
    private IncomingRecordBackHMapper incomingRecordBackHMapper;

    @Resource
    private IncomingRecordBackDMapper incomingRecordBackDMapper;

    @Resource
    private ReceivingRecordBackHMapper receivingRecordBackHMapper;

    @Resource
    private ReceivingRecordBackDMapper receivingRecordBackDMapper;

    @Resource
    private OrderInboundStatusBackService orderStatusBackService;

    @Value("${prolog.callSleepTimes:60000}") // 休眠1分钟
    private Long callSleepTimes;

    private static final String SERVICE_MSG = "异常行业务";
    private static Logger log = LoggerFactory.getLogger(ExceptionLinesServiceImpl.class);

    /**
     * 详情查询
     */
    @Override
    public ExceptionLineQueryDTO infoByPkId(String exceptionLineId) {
        AssertUtils.isNotBlank(exceptionLineId, SERVICE_MSG + OperationConstant.INFO_QUERY_OPERATION
                + OperationConstant.PK_NULL_MSG + "(exceptionLineId)");
        return this.mapper.findByPkId(exceptionLineId);
    }

    /**
     * 条件分页(携带额外数据)
     */
    @Override
    public Page<ExceptionLineQueryDTO> findList(ExceptionLineQueryVO queryVO) {
        AssertUtils.notNull(queryVO,
                SERVICE_MSG + OperationConstant.PAGE_QUERY_OPERATION + OperationConstant.QUERY_OBJ_NULL_MSG);
        this.startPage(queryVO);
        List<ExceptionLineQueryDTO> list = this.mapper.findList(queryVO);
        return PageUtils.getPage(list);
    }

    /**
     * 保存异常行数据
     */
    @Transactional
    @TxTransaction(isStart = true)
    @Override
    public Object saveList(List<ExceptionLinesDTO> exceptionLineDTOList, String masterId, UserDTO userDTO, Date now,
            boolean otherOp) {
        AssertUtils.isNotEmpty(exceptionLineDTOList, "保存的异常行数据不可为空!");
        if (ObjectUtils.isNull(userDTO))
            userDTO = userUtils.getUserDTO();
        if (ObjectUtils.isNull(now))
            now = new Date();
        log.info("异常行数据保存中:[{}]", now);
        boolean editFlag = Boolean.FALSE;
        int row = 0;
        Criteria crt1 = new Criteria(TaskQcDetail.class);
        Criteria crt2 = new Criteria(TaskQcRecheckDetail.class);
        Criteria crt3 = new Criteria(TaskInstockDetail.class);
        Criteria crt4 = new Criteria(TaskExceptionDetail.class);
        Criteria crt5 = new Criteria(RcvLines.class);

        // 任务更新数据
        Map<String, Object> map = new HashedMap<>();
        // 任务需要更新数据(其他字段)
        Map<String, Object> map2 = new HashedMap<>();
        // rcvLine需要更新数据
        Map<String, Object> map3 = new HashedMap<>();

        // step1: 循环行集合
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        List<String> preInstockLineId = new ArrayList<>();
        for (ExceptionLinesDTO dto : exceptionLineDTOList) {
            Date expiredDateNew = dto.getExpiredDateNew();
            Date productionDateNew = dto.getProductionDateNew();
            Date expiredDateOld = dto.getExpiredDateOld();
            Date productionDateOld = dto.getProductionDateOld();
            dto.setShowExpiredDateNew(DateUtils.format(expiredDateNew,"yyyyMMdd"));
            dto.setShowExpiredDateOld(DateUtils.format(expiredDateOld,"yyyyMMdd"));
            dto.setShowProductionDateOld(DateUtils.format(productionDateOld,"yyyyMMdd"));
            dto.setShowProductionDateNew(DateUtils.format(productionDateNew,"yyyyMMdd"));
            String showExpiredDateNew = dto.getShowExpiredDateNew();
            String showExpiredDateOld = dto.getShowExpiredDateOld();
            String showProductionDateOld = dto.getShowProductionDateOld();
            String showProductionDateNew = dto.getShowProductionDateNew();
            // 旧的最小单位总量
            BigDecimal pieceQtyOld = dto.getPieceQtyOld();
            // 新的最小单位总量
            BigDecimal pieceQtyNew = dto.getPieceQtyNew();
            if (!otherOp) {
                dto.setPieceQtyNew(BigDecimal.ZERO);
                pieceQtyNew = BigDecimal.ZERO;
            }
            row++;
            map.clear();
            map2.clear();
            map3.clear();
            if (!StringUtils.isBlank(showExpiredDateNew) && !StringUtils.isBlank(showProductionDateNew) && !StringUtils.isBlank(dto.getManufacturerLotNumNew())
                    && showExpiredDateNew.equals(showExpiredDateOld) &&  dto.getManufacturerLotNumNew().equals(dto.getManufacturerLotNumOld())
                    && showProductionDateOld.equals(showProductionDateNew) && pieceQtyOld.compareTo(pieceQtyNew) == 0) {
                throw new BizException(String.format("第[%d]行,没有修改任何异常数据!", row));
            }

            // step1: 先处理数量
            // 1.1: 修改数量不可大于原有数量
            // 只能改小,不能改大
            if (null != pieceQtyNew && pieceQtyOld.compareTo(pieceQtyNew) == -1)
                throw new BizException(String.format("第[%d]行,新修改的最小单位总量不能大于旧的最小单位总数量", row));

            // 数据准确性计算
            BigDecimal conversionRate = dto.getConversionRate();
            if (conversionRate == null) {
                conversionRate = BigDecimal.ONE;
                dto.setConversionRate(conversionRate);
            }
            if (pieceQtyNew != null) {
                BigDecimal caseQty = pieceQtyNew.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
                BigDecimal multiply = caseQty.multiply(conversionRate);
                BigDecimal oddPieceQty = pieceQtyNew.subtract(multiply); // 零散
                BigDecimal qty = pieceQtyNew.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
                // 保证数据正确性再次进行计算
                dto.setQtyNew(qty);
            }

            String exceptionHeaderId = dto.getExceptionHeaderId();
            if (ObjectUtils.isNull(exceptionHeaderId) && !ObjectUtils.isNull(masterId))
                dto.setExceptionHeaderId(masterId);
            // step2: 构建行默认字段
            this.buildDefaultField(dto, now, userDTO);
            // step3: 校验行字段
            this.vaildateModel(dto, editFlag, userDTO, row, validator,
                    SERVICE_MSG + OperationConstant.BATCH_ADD_OPERATION);
            // step4: 构建数据库基础字段
            ExceptionLines model = new ExceptionLines();
            // 创建日期出错
            // step5: 更新异常任务池状态(乐观锁控制并发)
//			String taskId = model.getTaskExceptionId();
            this.updateTaskStatus(dto, userDTO, now, row);
            BeanUtils.copyProperties(dto, model);
            this.setBaseSysField(model, editFlag, userDTO, now);
            // 批号不可修改 pass
            // 批号为*号的处理
            String manufacturerLotNumNew = model.getManufacturerLotNumNew();
            // 批号判断 为*或空增加当前时间100年
            if (!StringUtils.isBlank(manufacturerLotNumNew) && manufacturerLotNumNew.equals("*")) {
                model.setManufacturerLotNumNew("*");
                Date batchExpiredDate = model.getExpiredDateNew();
                Date batchProductionDate = model.getProductionDateNew();
                if (null == batchExpiredDate || null == batchProductionDate) {
                    // 日期归零
                    Date date = now;
                    date.setHours(0);
                    date.setMinutes(0);
                    date.setSeconds(0);
                    Date parse = null;
                    try {
                        parse = dateFormat.parse("2099-01-01");
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    model.setProductionDateNew(date);
                    model.setExpiredDateNew(parse);
                }
            }
            // 生产日期,效期,时分秒归零
            Date batchExpiredDate = model.getExpiredDateNew();
            Date batchProductionDate = model.getProductionDateNew();
            batchExpiredDate.setHours(0);
            batchExpiredDate.setMinutes(0);
            batchExpiredDate.setSeconds(0);
            model.setProductionDateNew(batchProductionDate);
            batchProductionDate.setHours(0);
            batchProductionDate.setMinutes(0);
            batchProductionDate.setSeconds(0);
            model.setExpiredDateNew(batchExpiredDate);
            model.setNodeTaskId(dto.getNodeTaskId());

            // step6: 保存行数据
            this.mapper.save(model);

            BeanUtils.copyProperties(model, dto);
            // step7: 修复错误的收货行及其对应任务
            String nodeType = dto.getNodeType();

            // 此处异常处理是否回传erp
            String nodeTaskId = dto.getNodeTaskId();
            if (nodeType.equals("40")) {
                // 来源上架节点需要清理预占
                preInstockLineId.add(nodeTaskId);
            }

        }

        // step8: 保存异常操作日志
        exceptionLogService.saveList(exceptionLineDTOList, userDTO, now);

        if (otherOp) {

            // Step9: 远程调用库存服务更新批号相关字段
            List<WmsInvBatchNumbers> batchNumbers = excuteUpdateBatchInfo(exceptionLineDTOList);
            for (ExceptionLinesDTO dto : exceptionLineDTOList) {
                WmsInvBatchNumbers batchNumbersBack = batchNumbers.stream().filter(x -> x.getBatchProductionDate().compareTo(dto.getProductionDateNew()) == 0
                        && x.getBatchExpiredDate().compareTo(dto.getExpiredDateNew()) == 0
                        && x.getManufacturerLotNum().equals(dto.getManufacturerLotNumNew())).findFirst().orElse(null);
                if(batchNumbersBack!=null){
                    dto.setBatchIdNew(batchNumbersBack.getBatchId());
                    dto.setBatchNumNew(batchNumbersBack.getBatchNum());
                }
                String nodeType = dto.getNodeType();
                if (otherOp) {
                    excuteHandleNode(nodeType, dto, map, map2, map3, crt1, crt2, crt3, crt4, crt5, row);
                }
            }

            // 清理预占
            if (!ObjectUtils.isNull(preInstockLineId)) {
                log.info("执行异常清理预占--------------------------------");
                InvStockCancel c = new InvStockCancel();
                c.setLineBillIds(preInstockLineId.toArray(new String[preInstockLineId.size()]));
                try {
                    RestMessage inCancel = baseInventoryRemoteCaller.inCancel(c);
                    if (inCancel != null && !inCancel.isSuccess()) {
                        log.info("异常远程调用清理预占,返回结果->", inCancel.getMessage() + inCancel.getData());
                    }
                } catch (Exception e) {
                    log.info("异常处理调用清理入库预占异常,原因{}", e);
                }
            }
        }

        // 不管是那个节点只要有上架的数据,都得判断回不回传
        String rcvHeaderId = exceptionLineDTOList.get(0).getRcvHeaderId();
        List<RcvInstockLines> findByMap = this.instockMapper
                .findByMap(MapUtils.put("rcvHeaderId", rcvHeaderId).getMap(), RcvInstockLines.class);
        if (ObjectUtils.isNull(findByMap)) {
            return true;
        }
        log.info("收货单id" + rcvHeaderId + "异常处理执行上架回传逻辑---------------------------------------");
//        this.instockService.excuteCallBackErp(findByMap, callSleepTimes * 1); // 2分钟
        if (vaildateRcvComplete(rcvHeaderId)) {
            //查询该收货单收货数量是否为0
            List<RcvLines> linesList = rcvLinesMapper.findByMap(MapUtils.put("rcvHeaderId", rcvHeaderId).getMap(), RcvLines.class);
            BigDecimal reduce = linesList.stream().map(x -> x.getPieceQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(reduce.compareTo(BigDecimal.ZERO)==0){
                return true;
            }
            // 执行数据保存 WMS_INF_CGRK_BILL
            excuteSaveCallBackData(rcvHeaderId);
            //青牛没有OMS，回传erp走接口平台自己组装数据
//            //收货拒收记录回传OMS
//            excuteRcvAndRejectBackOms(rcvHeaderId,userDTO);
//            //验收记录回传OMS
//            excuteRqcBackOms(rcvHeaderId,userDTO);
//            //上架完成回传OMS
//            excuteCallBackOms(rcvHeaderId);
            //            if (isExtCallBack) {
            //                // 额外回传
            //                excuteSaveExtCallBack(callList);
            //            }
        } else {
            log.info("整个收货单上架保存回传数据失败,数量不达标----------------------");
        }

        return true;
    }

    /**
     * 校验是否全部收货完成
     *
     * @param rcvHeaderId
     * @return
     */
    private boolean vaildateRcvComplete(String rcvHeaderId) {
        BigDecimal qty = null;
        try {
            qty = rcvHeadersMapper.getRemainQty(rcvHeaderId);
            log.info("收货剩余数量" + qty.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (qty == null) {
            throw new BizException(String.format("收货单id[%s]对应的收货明细总量查询为空!请检查!", rcvHeaderId));
        }
        if (qty != null && qty.compareTo(BigDecimal.ZERO) == 0) {
            return true;
        }
        return false;
    }

    private void excuteCallBackOms(String rcvHeaderId) {
        List<IncomingRecordBackVO> backList = new ArrayList<>();
        List<IncomingRecordBackHVO> backHVOList = incomingRecordBackHMapper.getInsertData(rcvHeaderId);
        if (backHVOList.size() > 0) {
            List<IncomingRecordBackDVO> backDList = incomingRecordBackDMapper.getInsertData(rcvHeaderId);
            for (IncomingRecordBackHVO incomingRecordBackHVO : backHVOList) {
                IncomingRecordBackVO backVO = new IncomingRecordBackVO();
                backVO.setContent(incomingRecordBackHVO);
                backVO.setDetailList(backDList);
                backList.add(backVO);
            }
            //TODO 调用接口平台回传OMS
            try {
//                String url = "http://integration.upcloud.prolog.org/api/rcvInstockLines/infTaskInBack";
//                if (StringUtils.isEmpty(incomingRecordBack)) {
//                    throw new BizException("请求路径配置为空");
//                }
//                System.out.println(JSON.toJSONString(backList));
//                String url = incomingRecordBack;
//                String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
//                JSONObject parse = JSONObject.parseObject(result);
                AskIntegrationVo vo = new AskIntegrationVo();
                vo.setIntegrationCode("incomingRecordBack");
                vo.setParam(backList);
                RestMessage<?> msg = baseInventoryRemoteCaller.askIntegration(vo);
                if (msg.isSuccess()) {
                    Criteria crt = Criteria.forClass(IncomingRecordH.class);
                    crt.restrictionBuilder().eq("billid", rcvHeaderId);
                    crt.buildRestriction();
                    incomingRecordHMapper.updateMapByCriteria(MapUtils.put("attrStr1", "Y").getMap(), crt);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            IncomingRecordBackHVO backHVO = backHVOList.get(0);
            orderStatusBackService.sendInboundOrderStatusOms(backHVO.getRefBillno(), "", "", backHVO.getBuyerName(), "", "130");
        }
    }

    private ReceivingRecordBackDVO convertBackDVORqc(ReceivingRecordBackD receivingRecordBackD){
        ReceivingRecordBackDVO backDVO = new ReceivingRecordBackDVO();
        BeanUtils.copyProperties(receivingRecordBackD,backDVO);
        backDVO.setSeqNo(receivingRecordBackD.getSeqno());
        backDVO.setRefSeqNo(receivingRecordBackD.getRefSeqno());
        backDVO.setBrandName(receivingRecordBackD.getItemname());
        backDVO.setCapacity(receivingRecordBackD.getCategoryId());
        backDVO.setFfactory(receivingRecordBackD.getManufacturer());
        backDVO.setPcs(receivingRecordBackD.getAffirmedPcs());
        backDVO.setOdd(receivingRecordBackD.getAffirmedOdd());
        backDVO.setQty(receivingRecordBackD.getAffirmedQty());
        backDVO.setAddress(receivingRecordBackD.getShipmentPlace());
        backDVO.setShipmentResult(receivingRecordBackD.getStockstatus());
        backDVO.setStartDate(receivingRecordBackD.getShipmentDate()!=null?DateUtils.format(receivingRecordBackD.getShipmentDate(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setTemperatureType(receivingRecordBackD.getTemperaturecType());
        backDVO.setAttainDate(receivingRecordBackD.getShipArriveTime()!=null?DateUtils.format(receivingRecordBackD.getShipArriveTime(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setAttainTemperature(receivingRecordBackD.getShipArriveTemPerature());
        backDVO.setTemperatureStatus(receivingRecordBackD.getTempcinfo());
        backDVO.setRegistrationNo(receivingRecordBackD.getItemHealthRegisterNbr());
        backDVO.setImportpaperno(receivingRecordBackD.getItemHealthRegisterNbrEn());
        backDVO.setFsymbol(receivingRecordBackD.getItemHealthApprovalNbr());
        backDVO.setOrign(receivingRecordBackD.getCountryOriginId());
        backDVO.setSterilizationLotNo(receivingRecordBackD.getSterilizesno());
        backDVO.setSterilizationDate(receivingRecordBackD.getSterilizeexpdate());
        backDVO.setCarrierType(receivingRecordBackD.getCarrierUnit());
        backDVO.setShipType(receivingRecordBackD.getShippingType());
        backDVO.setShipCompany(receivingRecordBackD.getCarriername());
        backDVO.setItemid(receivingRecordBackD.getItemid());
        backDVO.setPdateFrom(receivingRecordBackD.getPdateFrom()!=null?DateUtils.format(receivingRecordBackD.getPdateFrom(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setValidUntil(receivingRecordBackD.getValidUntil()!=null?DateUtils.format(receivingRecordBackD.getValidUntil(),"yyyy-MM-dd HH:mm:ss"):"");
        if(receivingRecordBackD.getStockstatus().equals("1")){
            backDVO.setResult("合格");
        }
        if(receivingRecordBackD.getStockstatus().equals("2")){
            backDVO.setResult("不合格");
        }
        if(receivingRecordBackD.getStockstatus().equals("3")){
            backDVO.setResult("待处理");
        }
        return backDVO;
    }

    private void excuteRqcBackOms(String rcvHeaderId,UserDTO userDTO) {
        List<RqcHeaders> rqcHeadersList = rqcHeadersMapper.findByMap(MapUtils.put("rcvHeaderId", rcvHeaderId).getMap(), RqcHeaders.class);
        for (RqcHeaders rqcHeadersDTO : rqcHeadersList) {
            //查询验收记录保存记录表
            List<ReceivingRecordBackVO> backList = new ArrayList<>();
            List<ReceivingRecordBackH> rqcInsertDataListH = receivingRecordBackHMapper.getRqcInsertData(rqcHeadersDTO.getRqcHeaderId());
            if (rqcInsertDataListH.size() > 0) {
                List<ReceivingRecordBackD> rqcInsertDataListD = receivingRecordBackDMapper.getRqcInsertData(rqcHeadersDTO.getRqcHeaderId());
                //验收明细
                List<ReceivingRecordBackDVO> rqcBackDVOList = new ArrayList<>();
                if (rqcInsertDataListD.size() > 0) {
                    for (ReceivingRecordBackD receivingRecordBackD : rqcInsertDataListD) {
                        if (!receivingRecordBackD.getStockstatus().equals("3")) {
                            ReceivingRecordBackDVO backDVO = convertBackDVORqc(receivingRecordBackD);
                            rqcBackDVOList.add(backDVO);
                        }
                    }
                } else {
                    continue;
                }
                for (ReceivingRecordBackH receivingRecordBackH : rqcInsertDataListH) {
                    ReceivingRecordBackVO backVO = new ReceivingRecordBackVO();
                    ReceivingRecordBackHVO backHVO = new ReceivingRecordBackHVO();
                    BeanUtils.copyProperties(receivingRecordBackH, backHVO);
                    backHVO.setRefBillno(receivingRecordBackH.getRefbillno());
                    backHVO.setGlBillno(receivingRecordBackH.getGlBillno());
                    backHVO.setPurorgId(receivingRecordBackH.getBuyerId());
                    backHVO.setPurorgName(receivingRecordBackH.getBuyerName());
                    backHVO.setShipmentDate(DateUtils.format(receivingRecordBackH.getRcvdate(), "yyyy-MM-dd HH:mm:ss"));
                    //backHVO.setRcvoperator(userDTO.getNickname());
                    backHVO.setPenterpriseid(receivingRecordBackH.getPEnterpriseid());
                    backHVO.setType("20");
                    backVO.setContent(backHVO);
                    backVO.setDetailList(rqcBackDVOList);
                    backList.add(backVO);
                }
                if (rqcInsertDataListH.size() > 0) {
                    receivingRecordBackHMapper.saveBatch(rqcInsertDataListH);
                }
                if (rqcInsertDataListD.size() > 0) {
                    receivingRecordBackDMapper.saveBatch(rqcInsertDataListD);
                }
                if (backList.size() == 0) {
                    return;
                }
                System.out.println(JSON.toJSONString(backList));
                //TODO 调用接口平台推送验收记录数据到OMS
                try {
                    if (rqcBackDVOList.size() > 0) {
                        //                String url = "http://integration.upcloud.prolog.org/api/rcvInstockLines/infTaskInBack";
//                    if(StringUtils.isEmpty(receivingRecordBack)){
//                        throw new BizException("请求路径配置为空");
//                    }
//                    System.out.println(JSON.toJSONString(backList));
//                    String url = receivingRecordBack;
//                    String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
//                    JSONObject parse = JSONObject.parseObject(result);
                        AskIntegrationVo vo = new AskIntegrationVo();
//                        vo.setIntegrationCode("receivingRecordBack");
                        vo.setParam(backList);
                        RestMessage<?> msg = baseInventoryRemoteCaller.askIntegration(vo);
                        if (msg.isSuccess()) {
                            String[] billids = rqcInsertDataListH.stream().map(x -> x.getBillid()).toArray(String[]::new);
                            Criteria crt = Criteria.forClass(ReceivingRecordBackH.class);
                            crt.restrictionBuilder().in("billid", billids);
                            crt.buildRestriction();
                            receivingRecordBackHMapper.updateMapByCriteria(MapUtils.put("uploadStatus", "1").getMap(), crt);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void excuteRcvAndRejectBackOms(String rcvHeaderId,UserDTO userDTO){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        //保存记录到收货-拒收-验收记录表
        List<ReceivingRecordBackVO> backList = new ArrayList<>();
        List<ReceivingRecordBackH> backHList = receivingRecordBackHMapper.getRcvInsertData(rcvHeaderId);
        if(backHList.size()>0){
            List<ReceivingRecordBackD> backDList = receivingRecordBackDMapper.getRcvInsertData(rcvHeaderId);
            //收货明细
            List<ReceivingRecordBackDVO> rcvBackDVOList = new ArrayList<>();
            //拒收明细
            List<ReceivingRecordBackDVO> rejectBackDVOList = new ArrayList<>();
            if(backDList.size()>0){
                for (ReceivingRecordBackD receivingRecordBackD : backDList) {
                    ReceivingRecordBackDVO backDVO = convertBackDVO(receivingRecordBackD);
                    if(receivingRecordBackD.getStockstatus().equals("2")){
                        rejectBackDVOList.add(backDVO);
                    }else{
                        rcvBackDVOList.add(backDVO);
                    }
                }
            }
            if(rcvBackDVOList.size()>0){
                for (ReceivingRecordBackH receivingRecordBackH : backHList) {
                    ReceivingRecordBackVO backVO = new ReceivingRecordBackVO();
                    ReceivingRecordBackHVO backHVO = new ReceivingRecordBackHVO();
                    BeanUtils.copyProperties(receivingRecordBackH,backHVO);
                    backHVO.setRefBillno(receivingRecordBackH.getRefbillno());
                    backHVO.setPurorgId(receivingRecordBackH.getBuyerId());
                    backHVO.setPurorgName(receivingRecordBackH.getBuyerName());
                    backHVO.setShipmentDate(DateUtils.format(receivingRecordBackH.getRcvdate(),"yyyy-MM-dd HH:mm:ss"));
                    //backHVO.setRcvoperator(userDTO.getNickname());
                    backHVO.setPenterpriseid(receivingRecordBackH.getPEnterpriseid());
                    backHVO.setType("10");
                    backVO.setContent(backHVO);
                    backVO.setDetailList(rcvBackDVOList);
                    backList.add(backVO);
                }
            }
            if(rejectBackDVOList.size()>0){
                for (ReceivingRecordBackH receivingRecordBackH : backHList) {
                    ReceivingRecordBackVO backVO = new ReceivingRecordBackVO();
                    ReceivingRecordBackHVO backHVO = new ReceivingRecordBackHVO();
                    BeanUtils.copyProperties(receivingRecordBackH,backHVO);
                    backHVO.setRefBillno(receivingRecordBackH.getRefbillno());
                    backHVO.setPurorgId(receivingRecordBackH.getBuyerId());
                    backHVO.setPurorgName(receivingRecordBackH.getBuyerName());
                    backHVO.setShipmentDate(DateUtils.format(receivingRecordBackH.getRcvdate(),"yyyy-MM-dd HH:mm:ss"));
                    //backHVO.setRcvoperator(userDTO.getNickname());
                    backHVO.setPenterpriseid(receivingRecordBackH.getPEnterpriseid());
                    backHVO.setType("30");
                    backVO.setContent(backHVO);
                    backVO.setDetailList(rejectBackDVOList);
                    backList.add(backVO);
                }
            }
            receivingRecordBackHMapper.saveBatch(backHList);
            receivingRecordBackDMapper.saveBatch(backDList);
            //TODO 调用接口平台回传OMS
            try {
//                String url = "http://integration.upcloud.prolog.org/api/rcvInstockLines/infTaskInBack";
//                if(StringUtils.isEmpty(receivingRecordBack)){
//                    throw new BizException("请求路径配置为空");
//                }
                System.out.println(JSON.toJSONString(backList));
                //String url = receivingRecordBack;
                AskIntegrationVo vo = new AskIntegrationVo();
//                vo.setIntegrationCode("receivingRecordBack"); //青牛没有OMS
                vo.setParam(backList);
                RestMessage<?> msg = baseInventoryRemoteCaller.askIntegration(vo);
//                String result = HttpUtil.post(url, JSONObject.toJSONString(backList));
//                JSONObject parse = JSONObject.parseObject(result);
                if(msg.isSuccess()){
                    String[] billids = backHList.stream().map(x -> x.getBillid()).toArray(String[]::new);
                    Criteria crt = Criteria.forClass(ReceivingRecordBackH.class);
                    crt.restrictionBuilder().in("billid",billids);
                    crt.buildRestriction();
                    receivingRecordBackHMapper.updateMapByCriteria(MapUtils.put("uploadStatus","1").getMap(),crt);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

    private ReceivingRecordBackDVO convertBackDVO(ReceivingRecordBackD receivingRecordBackD){
        ReceivingRecordBackDVO backDVO = new ReceivingRecordBackDVO();
        BeanUtils.copyProperties(receivingRecordBackD,backDVO);
        backDVO.setSeqNo(receivingRecordBackD.getSeqno());
        backDVO.setRefSeqNo(receivingRecordBackD.getRefSeqno());
        backDVO.setBrandName(receivingRecordBackD.getItemname());
        backDVO.setCapacity(receivingRecordBackD.getCategoryId());
        backDVO.setFfactory(receivingRecordBackD.getManufacturer());
        backDVO.setPcs(receivingRecordBackD.getAffirmedPcs());
        backDVO.setOdd(receivingRecordBackD.getAffirmedOdd());
        backDVO.setQty(receivingRecordBackD.getAffirmedQty());
        backDVO.setAddress(receivingRecordBackD.getShipmentPlace());
        backDVO.setShipmentResult(receivingRecordBackD.getStockstatus());
        backDVO.setStartDate(receivingRecordBackD.getShipmentDate()!=null?DateUtils.format(receivingRecordBackD.getShipmentDate(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setTemperatureType(receivingRecordBackD.getTemperaturecType());
        backDVO.setAttainDate(receivingRecordBackD.getShipArriveTime()!=null?DateUtils.format(receivingRecordBackD.getShipArriveTime(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setAttainTemperature(receivingRecordBackD.getShipArriveTemPerature());
        backDVO.setTemperatureStatus(receivingRecordBackD.getTempcinfo());
        backDVO.setRegistrationNo(receivingRecordBackD.getItemHealthRegisterNbr());
        backDVO.setImportpaperno(receivingRecordBackD.getItemHealthRegisterNbrEn());
        backDVO.setFsymbol(receivingRecordBackD.getItemHealthApprovalNbr());
        backDVO.setOrign(receivingRecordBackD.getCountryOriginId());
        backDVO.setSterilizationLotNo(receivingRecordBackD.getSterilizesno());
        backDVO.setSterilizationDate(receivingRecordBackD.getSterilizeexpdate());
        backDVO.setCarrierType(receivingRecordBackD.getCarrierUnit());
        backDVO.setShipType(receivingRecordBackD.getShippingType());
        backDVO.setShipCompany(receivingRecordBackD.getCarriername());
        backDVO.setItemid(receivingRecordBackD.getItemid());
        backDVO.setPdateFrom(receivingRecordBackD.getPdateFrom()!=null?DateUtils.format(receivingRecordBackD.getPdateFrom(),"yyyy-MM-dd HH:mm:ss"):"");
        backDVO.setValidUntil(receivingRecordBackD.getValidUntil()!=null?DateUtils.format(receivingRecordBackD.getValidUntil(),"yyyy-MM-dd HH:mm:ss"):"");
        if(receivingRecordBackD.getStockstatus().equals("1")){
            backDVO.setResult("合格");
        }
        if(receivingRecordBackD.getStockstatus().equals("2")){
            backDVO.setResult("拒收");
        }
        if(receivingRecordBackD.getStockstatus().equals("3")){
            backDVO.setResult("待处理");
        }
        return backDVO;
    }

    private void excuteSaveCallBackData(String rcvHeaderId) {
        IncomingRecordQueryVO vo = new IncomingRecordQueryVO();
        AssertUtils.isNotBlank(rcvHeaderId, "收货单单id不可为空!");
        List<String> rcvHeaderIds = new ArrayList<>();
        rcvHeaderIds.add(rcvHeaderId);
        vo.setRcvHeaderIds(rcvHeaderIds);

        List<IncomingRecordH> insertData1 = this.incomingRecordHMapper.getInsertData(vo);
        List<IncomingRecordH> insertData = new ArrayList<>();
        for (IncomingRecordH insertDatum : insertData1) {
            List<IncomingRecordH> billid = incomingRecordHMapper.findByMap(MapUtils.put("billid", insertDatum.getBillid()).getMap(), IncomingRecordH.class);
            if(billid.size()==0){
                insertData.add(insertDatum);
            }
        }
        if (ObjectUtils.isNotNull(insertData)) {
            this.incomingRecordHMapper.saveBatch(insertData);
        }
        List<IncomingRecordD> insertDataD1 = this.incomingRecordDMapper.getInsertData(vo);
        List<IncomingRecordD> insertDataD = new ArrayList<>();
        for (IncomingRecordD incomingRecordD : insertDataD1) {
            List<IncomingRecordD> lineId = incomingRecordDMapper.findByMap(MapUtils.put("lineId", incomingRecordD.getLineId()).getMap(), IncomingRecordD.class);
            if(lineId.size()==0){
                insertDataD.add(incomingRecordD);
            }
        }
        if (ObjectUtils.isNotNull(insertData)) {
            this.incomingRecordDMapper.saveBatch(insertDataD);
        }
    }
//	/**
//	 * 保存异常行数据
//	 */
//	@Transactional
//	@Override
//	public Object saveList(List<ExceptionLinesDTO> exceptionLineDTOList, String masterId, UserDTO userDTO, Date now) {
//		if (ObjectUtils.isNull(userDTO))
//			userDTO = userUtils.getUserDTO();
//		if (ObjectUtils.isNull(now))
//			now = new Date();
//		log.info("异常行数据保存中:[{}]", now);
//		boolean editFlag = Boolean.FALSE;
//		int row = 0;
//		Criteria crt1 = new Criteria(TaskQcDetail.class);
//		Criteria crt2 = new Criteria(TaskQcRecheckDetail.class);
//		Criteria crt3 = new Criteria(TaskInstockDetail.class);
//		Criteria crt4 = new Criteria(TaskExceptionDetail.class);
//		Criteria crt5 = new Criteria(RcvLines.class);
//		
//		// 任务更新数据
//		Map<String, Object> map = new HashedMap<>();
//		// 任务需要更新数据(其他字段)
//		Map<String, Object> map2 = new HashedMap<>();
//		// rcvLine需要更新数据
//		Map<String, Object> map3 = new HashedMap<>();
//		
//		// step1: 循环行集合
//		DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
//		for (ExceptionLinesDTO dto : exceptionLineDTOList) {
//			String showExpiredDateNew = dto.getShowExpiredDateNew();
//			String showExpiredDateOld = dto.getShowExpiredDateOld();
//			String showProductionDateOld = dto.getShowProductionDateOld();
//			String showProductionDateNew = dto.getShowProductionDateNew();
//			// 旧的最小单位总量
//			BigDecimal pieceQtyOld = dto.getPieceQtyOld();
//			// 新的最小单位总量
//			BigDecimal pieceQtyNew = dto.getPieceQtyNew();
//			if (showExpiredDateNew.equals(showExpiredDateOld) && showProductionDateOld.equals(showProductionDateNew)
//					&& pieceQtyOld.compareTo(pieceQtyNew) == 0) {
//				throw new BizException("没有修改任何异常数据!");
//			}
//			map.clear();
//			map2.clear();
//			map3.clear();
//			
//			row++;
//			
//			// 数据准确性计算
//			BigDecimal conversionRate = dto.getConversionRate();
//			if (conversionRate == null) {
//				conversionRate = BigDecimal.ONE;
//				dto.setConversionRate(conversionRate);
//			}
//			if (pieceQtyNew != null) {
//				BigDecimal caseQty = pieceQtyNew.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
//				BigDecimal multiply = caseQty.multiply(conversionRate);
//				BigDecimal oddPieceQty = pieceQtyNew.subtract(multiply); // 零散
//				BigDecimal qty = pieceQtyNew.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
//				// 保证数据正确性再次进行计算
//				dto.setQtyNew(qty);
//			}
//			
//			// 只能改小,不能改大
//			if (null != pieceQtyNew && pieceQtyOld.compareTo(pieceQtyNew) == -1)
//				throw new BizException("新修改的最小单位总量不能大于旧的最小单位总数量");
//			
//			String exceptionHeaderId = dto.getExceptionHeaderId();
//			if (ObjectUtils.isNull(exceptionHeaderId) && !ObjectUtils.isNull(masterId))
//				dto.setExceptionHeaderId(masterId);
//			// step2: 构建行默认字段
//			this.buildDefaultField(dto, now, userDTO);
//			// step3: 校验行字段
//			this.vaildateModel(dto, editFlag, userDTO, row, validator,
//					SERVICE_MSG + OperationConstant.BATCH_ADD_OPERATION);
//			// step4: 构建数据库基础字段
//			ExceptionLines model = new ExceptionLines();
//			BeanUtils.copyProperties(dto, model);
//			// 创建日期出错
//			this.setBaseSysField(model, editFlag, userDTO, now);
////			this.buildField(model, editFlag, userDTO,now);
//			// step5: 更新异常任务池状态(乐观锁控制并发)
//			String taskId = model.getTaskExceptionId();
//			this.updateTaskStatus(taskId, userDTO, now, row);
//			
//			// 批号不可修改 pass
//			// 批号为*号的处理
//			String manufacturerLotNumNew = model.getManufacturerLotNumNew();
//			// 批号判断 为*或空增加当前时间100年
//			if (!StringUtils.isBlank(manufacturerLotNumNew) && manufacturerLotNumNew.equals("*")) {
//				model.setManufacturerLotNumNew("*");
//				Date batchExpiredDate = model.getExpiredDateNew();
//				Date batchProductionDate = model.getProductionDateNew();
//				if (null == batchExpiredDate || null == batchProductionDate) {
//					// 日期归零
//					Date date = now;
//					date.setHours(0);
//					date.setMinutes(0);
//					date.setSeconds(0);
//					Date parse = null;
//					try {
//						parse = dateFormat.parse("2099-01-01");
//					} catch (ParseException e) {
//						e.printStackTrace();
//					}
//					model.setProductionDateNew(date);
//					model.setExpiredDateNew(parse);
//				}
//			}
//			// 生产日期,效期,时分秒归零
//			Date batchExpiredDate = model.getExpiredDateNew();
//			Date batchProductionDate = model.getProductionDateNew();
//			batchExpiredDate.setHours(0);
//			batchExpiredDate.setMinutes(0);
//			batchExpiredDate.setSeconds(0);
//			model.setProductionDateNew(batchProductionDate);
//			batchProductionDate.setHours(0);
//			batchProductionDate.setMinutes(0);
//			batchProductionDate.setSeconds(0);
//			model.setExpiredDateNew(batchExpiredDate);
//			
//			// 校验批号信息是否重复
////			RcvLineLotInfo rcvLineLotInfo = new RcvLineLotInfo();
////			String itemId = model.getItemId();
////			String mtlOwnerId = model.getMtlOwnerId();
////			String warehouseId = model.getWarehouseId();
////			String showExpiredDateNew = model.getShowExpiredDateNew();
////			String showProductionDateNew = model.getShowProductionDateNew();
////			rcvLineLotInfo.setEnterpriseId(userDTO.getEnterpriseId());
////			rcvLineLotInfo.setShowExpiredDate(showExpiredDateNew);
////			rcvLineLotInfo.setShowProductionDate(showProductionDateNew);
////			rcvLineLotInfo.setMtlOwnerId(mtlOwnerId);
////			rcvLineLotInfo.setManufacturerLotNum(manufacturerLotNumNew);
////			rcvLineLotInfo.setWarehouseId(warehouseId);
////			rcvLineLotInfo.setItemId(itemId);
////			rcvLinesService.excuteVaildateRcvItemLotNum(rcvLineLotInfo, row);
//			
//			// 是否需要调用库存服务生成新的批次id,批次号? TODO
//			
//			// step6: 保存行数据
//			this.mapper.save(model);
//			
//			BeanUtils.copyProperties(model, dto);
//			// step7: 修复错误的收货行及其对应任务
//			String nodeType = dto.getNodeType();
//			
//			excuteHandleNode(nodeType, dto, map, map2, map3, crt1, crt2, crt3, crt4, crt5, row);
//			
//			// 此处异常处理是否回传erp
//			
//		}
//		
//		// step8: 保存异常操作日志
//		exceptionLogService.saveList(exceptionLineDTOList, userDTO, now);
//		
//		// Step9: 远程调用库存服务更新批号相关字段
//		excuteUpdateBatchInfo(exceptionLineDTOList);
//		
//		return true;
//	}

    @Transactional
    public void excuteHandleNode(String nodeType, ExceptionLinesDTO dto, Map<String, Object> map,
            Map<String, Object> map2, Map<String, Object> map3, Criteria crt1, Criteria crt2, Criteria crt3,
            Criteria crt4, Criteria crt5, int row) {
        // 可优化成一个方法实现
        if (BizConstant.WMS_EXCEPTION_NODE_RCV.replace("\"", "").equals(nodeType.trim())) {
            // 预留处理
        }
        if (BizConstant.WMS_EXCEPTION_NODE_RQC.replace("\"", "").equals(nodeType.trim())) {
            // 质检节点异常处理
            excuteUpdateQcTask(dto, map, map2, map3, crt1, crt2, crt3, crt4, crt5, row);
        }
        if (BizConstant.WMS_EXCEPTION_NODE_RERQC.replace("\"", "").equals(nodeType.trim())) {

        }
        if (BizConstant.WMS_EXCEPTION_NODE_INSTOCK.replace("\"", "").equals(nodeType.trim())) {
            // 上架节点异常处理
            excuteUpdateInstockTask(dto, map, map2, map3, crt1, crt2, crt3, crt4, crt5, row);
        }

    }

    /**
     * 更新库存批次信息
     * 
     * @param exceptionLineDTOList
     */
    private List<WmsInvBatchNumbers> excuteUpdateBatchInfo(List<ExceptionLinesDTO> exceptionLineDTOList) {
        ValidList<InvStockBatchNumberUpdate> updateList = new ValidList<>();

        for (ExceptionLinesDTO exceptionLinesDTO : exceptionLineDTOList) {
            String showExpiredDateNew = exceptionLinesDTO.getShowExpiredDateNew();
            String showExpiredDateOld = exceptionLinesDTO.getShowExpiredDateOld();
            String showProductionDateOld = exceptionLinesDTO.getShowProductionDateOld();
            String showProductionDateNew = exceptionLinesDTO.getShowProductionDateNew();
            String manufacturerLotNumNew = exceptionLinesDTO.getManufacturerLotNumNew();
            String manufacturerLotNumOld = exceptionLinesDTO.getManufacturerLotNumOld();

            if ((!StringUtils.isBlank(showExpiredDateNew) && !showExpiredDateNew.equals(showExpiredDateOld))
                    || (!StringUtils.isBlank(showProductionDateNew)
                        && !showProductionDateOld.equals(showProductionDateNew))
                    ||(!StringUtils.isBlank(manufacturerLotNumNew)&& !manufacturerLotNumNew.equals(manufacturerLotNumOld))) {
                // 修改了批次信息
                InvStockBatchNumberUpdate BatchInfo = new InvStockBatchNumberUpdate();
                String batchIdOld = exceptionLinesDTO.getBatchIdOld();
                Date expiredDateNew = exceptionLinesDTO.getExpiredDateNew();
                Date productionDateNew = exceptionLinesDTO.getProductionDateNew();

                BatchInfo.setBatchId(batchIdOld);
                BatchInfo.setBatchExpiredDate(expiredDateNew);
                BatchInfo.setBatchProductionDate(productionDateNew);
                BatchInfo.setBatchExpiredDateShow(showExpiredDateNew);
                BatchInfo.setBatchProductionDateShow(showProductionDateNew);
				BatchInfo.setManufacturerLotNum(exceptionLinesDTO.getManufacturerLotNumNew());
                updateList.add(BatchInfo);
            }
        }

        List<WmsInvBatchNumbers> data = new ArrayList<>();
        try {
            if (!ObjectUtils.isNull(updateList)) {
                log.info(JSON.toJSONString(updateList));
                RestMessage<List<WmsInvBatchNumbers>> updateBatchNumber = baseInventoryRemoteCaller.updateBatchNumberBack(updateList);
                if (updateBatchNumber != null && !updateBatchNumber.isSuccess()) {
                    log.info("更新库存批次信息失败,原因->", updateBatchNumber.getMessage() + updateBatchNumber.getData());
                }else{
                    data = updateBatchNumber.getData();
                }
            }
        } catch (Exception e) {
            // 打印错误
            log.info("更新库存批次信息失败,原因->", e);
        }
        // 看这里是否回传erp/oms TODO
        return data;
    }

    private void buildField(ExceptionLines model, boolean editFlag, UserDTO userDTO, Date now) {
        // 构建系统字段
        String username = userDTO.getUsername();
        String id = userDTO.getId();
        if (!editFlag) {
            model.setCreator(id);
            model.setCreatorName(username);
//			model.setGmtCreate(now);
        }
        model.setModifier(id);
        model.setModifierName(username);
        model.setGmtModified(now);
    }

    /**
     * 
     * @Description: 执行错误修复(上架节点)
     * @param dto
     * @param row
     */
    private void excuteUpdateInstockTask(ExceptionLinesDTO dto, Map<String, Object> map, Map<String, Object> map2,
            Map<String, Object> map3, Criteria crt1, Criteria crt2, Criteria crt3, Criteria crt4, Criteria crt5,
            int row) {
        String nodeTaskId = dto.getNodeTaskId();
        BigDecimal pieceQtyNew = dto.getPieceQtyNew();
        log.info("开始执行上架错误节点处理---------------------------------------------");
        TaskInstockDetail detail = taskInstockDetailMapper.findById(nodeTaskId, TaskInstockDetail.class);
        AssertUtils.notNull(detail, "异常出现的节点(上架)任务为空!");

        // 包装含量
        BigDecimal conversionRate = dto.getConversionRate();

        // 新的过期时间
        Date expiredDateNew = dto.getExpiredDateNew();
        // 新的生产时间
        Date productionDateNew = dto.getProductionDateNew();
        // 新的qty
        BigDecimal qtyNew = dto.getQtyNew();
        String showExpiredDateNew = dto.getShowExpiredDateNew();
        String showExpiredDateOld = dto.getShowExpiredDateOld();
        String showProductionDateOld = dto.getShowProductionDateOld();
        String showProductionDateNew = dto.getShowProductionDateNew();
        String manufacturerLotNumOld = dto.getManufacturerLotNumOld();
        String manufacturerLotNumNew = dto.getManufacturerLotNumNew();
        BigDecimal pieceQtyOld = dto.getPieceQtyOld();

        if ((!StringUtils.isBlank(showExpiredDateNew) && !showExpiredDateNew.equals(showExpiredDateOld))
                || (!StringUtils.isBlank(showProductionDateNew)
                && !showProductionDateOld.equals(showProductionDateNew))||(!StringUtils.isBlank(manufacturerLotNumNew)
                && !manufacturerLotNumOld.equals(manufacturerLotNumNew))) {
            // 校验批次是否有库存信息,是否可调整. TODO
            map.put("status", "1"); // 任务可执行
            //excuteVaildateBatchHasInstock(dto, row);
            // 修改了批次信息
            if (ObjectUtils.isNotNull(expiredDateNew)) {
                map3.put("batchExpiredDate", expiredDateNew);
            }
            if (ObjectUtils.isNotNull(productionDateNew)) {
                map3.put("batchProductionDate", productionDateNew);
            }
            if (ObjectUtils.isNotNull(showProductionDateNew)) {
                map3.put("showProductionDate", showProductionDateNew);
            }
            if (ObjectUtils.isNotNull(showExpiredDateNew)) {
                map3.put("showExpiredDate", showExpiredDateNew);
            }
            if (ObjectUtils.isNotNull(manufacturerLotNumNew)) {
                map3.put("manufacturerLotNum", manufacturerLotNumNew);
                map.put("manufacturerLotNum", manufacturerLotNumNew);
            }
            map.put("batchId",dto.getBatchIdNew());
            map.put("batchNum",dto.getBatchNumNew());
            map3.put("batchId",dto.getBatchIdNew());
            map3.put("batchNum",dto.getBatchNumNew());
        }

        if (null != pieceQtyNew && pieceQtyOld.compareTo(pieceQtyNew) == 1) {
            // 修改了数量
            map.put("pieceQty", pieceQtyNew);
            map.put("gmtModified", new Date());
            if (BigDecimal.ZERO.compareTo(pieceQtyNew) == 0) {
                // 数量为0
                map.put("qty", BigDecimal.ZERO);
            } else {
                // 不为0
                map.put("status", "1"); // 任务可执行
                if (null == qtyNew) {
                    if (null == conversionRate || conversionRate.compareTo(BigDecimal.ZERO) == 0) {
                        map.put("qty", pieceQtyNew);
                        map.put("conversionRate", 1);
                    } else {
                        map.put("qty", pieceQtyNew.divide(conversionRate, 2, BigDecimal.ROUND_DOWN));
                    }
                } else {
                    map.put("qty", qtyNew);
                }
            }
//			// 更新对应的错误节点任务的数据(乐观锁)
//			Integer dataVersion = detail.getDataVersion();
//			crt3.setRestriction(
//					Restrictions.eq("dataVersion", dataVersion).and(Restrictions.eq("taskInboundId", nodeTaskId)));
//			long l1 = this.taskInstockDetailMapper.updateMapByCriteria(map, crt3);
//			if (l1 <= 0)
//				// 更新失败(有人在操作)
//				throw new BizException(String.format("第[%d]行,异常来源节点的任务(上架)id:[%s]查询的任务操作中,请刷新重试!", row, nodeTaskId));
            BigDecimal subtract = pieceQtyOld.subtract(pieceQtyNew);
            map3.put("diffPieceQty", subtract);
//			log.info("结束执行上架错误节点处理---------------------------------------------");
        }

        if (!ObjectUtils.isNull(map3) && map3.containsKey("diffPieceQty")) {
            String rqcLineId = detail.getRqcLineId();
            RqcLines rqcLines = rqcLinesMapper.findById(rqcLineId, RqcLines.class);
            BigDecimal diffPieceQty = (BigDecimal) map3.get("diffPieceQty");
            // 更新对应的质检行
            if (null != rqcLines && BigDecimal.ZERO.compareTo(diffPieceQty) == -1) {
                String taskRqcId = rqcLines.getTaskRqcId();
                BigDecimal pieceQty = rqcLines.getPieceQty();
                conversionRate = rqcLines.getConversionRate();
                pieceQty = pieceQty.subtract(diffPieceQty);
                rqcLines.setPieceQty(pieceQty);
                // 更新质检数量
                BigDecimal caseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
                BigDecimal multiply = caseQty.multiply(conversionRate);
                BigDecimal oddPieceQty = pieceQty.subtract(multiply); // 零散
                BigDecimal qty = pieceQty.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
                rqcLines.setOddCaseQty(caseQty);
                rqcLines.setOddPieceQty(oddPieceQty);
                rqcLinesMapper.update(rqcLines);

                // 更新验收任务
                taskQcDetailMapper.updateMapById(taskRqcId,
                        MapUtils.put("segment1", "1").put("qty", qty).put("pieceQty", pieceQty).getMap(),
                        TaskQcDetail.class);

                // 更新抽检数量
                Criteria crt11 = Criteria.forClass(WmsInRqcSample.class);
                crt11.setRestriction(Restrictions.eq("taskRqcId", taskRqcId));
                List<WmsInRqcSample> rqcSamples = rqcSampleMapper.findByCriteria(crt11);
                if (!ObjectUtils.isNull(rqcSamples) && !ObjectUtils.isNull(rqcSamples.get(0))) {
                    WmsInRqcSample rqcSample = rqcSamples.get(0);
                    BigDecimal pieceQty2 = rqcSample.getPieceQty();
                    pieceQty2 = pieceQty2.subtract(diffPieceQty);
                    rqcSample.setPieceQty(pieceQty2);
                    BigDecimal caseQty2 = pieceQty2.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
                    BigDecimal multiply2 = caseQty2.multiply(conversionRate);
                    BigDecimal oddPieceQty2 = pieceQty.subtract(multiply2); // 零散
                    rqcSample.setOddCaseQty(caseQty2);
                    rqcSample.setOddPieceQty(oddPieceQty2);
                    BigDecimal qcOddPieceQty = rqcSample.getQcOddPieceQty();
                    BigDecimal qcOddCaseQty = rqcSample.getQcOddCaseQty();
                    BigDecimal add = qcOddCaseQty.multiply(conversionRate).add(qcOddPieceQty);
                    if (add.compareTo(pieceQty2) == 1) {
                        rqcSample.setQcOddCaseQty(caseQty2);
                        rqcSample.setQcOddPieceQty(oddPieceQty2);
                    }
                    BigDecimal qcOddCaseActQty = rqcSample.getQcOddCaseActQty();
                    BigDecimal qcOddPieceActQty = rqcSample.getQcOddPieceActQty();
                    BigDecimal add2 = qcOddCaseActQty.multiply(conversionRate).add(qcOddPieceActQty);
                    if (add2.compareTo(pieceQty2) == 1) {
                        rqcSample.setQcOddCaseActQty(caseQty2);
                        rqcSample.setQcOddPieceActQty(oddPieceQty2);
                    }
                    rqcSampleMapper.update(rqcSample);
                }

                // 更新复检以及复检任务
                Integer refType = rqcLines.getRefType();
                if (refType != null && 2 == refType) {
                    String refLineId = rqcLines.getRefLineId();
                    RqcReLines rqcReLines = rqcReLinesMapper.findById(refLineId, RqcReLines.class);
                    if (rqcReLines != null) {

                        BigDecimal pieceQty3 = rqcReLines.getPieceQty();
                        pieceQty3 = pieceQty3.subtract(diffPieceQty);
                        rqcReLines.setPieceQty(pieceQty3);
                        BigDecimal caseQty3 = pieceQty3.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
                        BigDecimal multiply3 = caseQty3.multiply(conversionRate);
                        BigDecimal oddPieceQty3 = pieceQty3.subtract(multiply3); // 零散
                        BigDecimal qty3 = pieceQty3.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
                        rqcReLines.setOddCaseQty(caseQty3);
                        rqcReLines.setOddPieceQty(oddPieceQty3);
                        rqcReLinesMapper.update(rqcReLines);

                        // 更新复检任务
                        taskQcRecheckDetailMapper.updateMapById(rqcReLines.getTaskReRqcId(),
                                MapUtils.put("segment1", "1").put("qty", qty3).put("pieceQty", pieceQty3).getMap(),
                                TaskQcRecheckDetail.class);
                    }
                }
            }
        }

        // 更新对应的错误节点任务的数据(乐观锁)
        Integer dataVersion = detail.getDataVersion();

        Restriction eq = Restrictions.eq("dataVersion", dataVersion);
        Restriction eq2 = Restrictions.eq("taskInboundId", nodeTaskId);
        Restriction eq3 = Restrictions.eq("status", "0"); // 不可执行
        crt3.setRestriction(Restrictions.and(eq, eq2, eq3));
        map.put("dataVersion", dataVersion + 1);
        long l1 = this.taskInstockDetailMapper.updateMapByCriteria(map, crt3);
        if (l1 <= 0)
            // 更新失败(有人在操作)
            throw new BizException(String.format("第[%d]行,异常来源节点的任务(上架)id:[%s]查询的任务操作中,请刷新重试!", row, nodeTaskId));
        BigDecimal subtract = pieceQtyOld.subtract(pieceQtyNew);
        map3.put("diffPieceQty", subtract);
        log.info("结束执行上架错误节点处理---------------------------------------------");

        // 更新所有的rcvlineId所对应的task
        crt3.setRestriction(null);

        // 更新收货行信息表
        // 更新的数据过多,建议关联查询
        excuteUpdateTask(dto, map2, map3, crt1, crt2, crt3, crt4, crt5);

    }

    private void excuteVaildateBatchHasInstock(ExceptionLinesDTO dto, int row) {
        Set<String> set = new HashSet<>();
        String batchIdOld = dto.getBatchIdOld();
        set.add(batchIdOld);
        Map<String, Boolean> excuteVaildateHasInstock = excuteVaildateHasInstock(dto.getWarehouseId(), set);
        if (!ObjectUtils.isNull(excuteVaildateHasInstock)) {
            Boolean boolean1 = excuteVaildateHasInstock.get(batchIdOld);
            if (boolean1) {
                throw new BizException(String.format("第[%d]行,批号[%s]对应的批次[%s]信息已有进销存记录,若要修改,请联系相关人员进行批次调整操作!", row,
                        dto.getManufacturerLotNumOld(), batchIdOld));
            }
        }

    }

    /**
     * 
     * @Description: 更新任务池其他数据
     */
    private void excuteUpdateTask(ExceptionLinesDTO dto, Map<String, Object> map2, Map<String, Object> map3,
            Criteria crt1, Criteria crt2, Criteria crt3, Criteria crt4, Criteria crt5) {
        String rcvLineId = dto.getRcvLineId();
        if (!ObjectUtils.isNull(map2)) {
            // 更新质检任务
            crt1.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
            this.taskQcDetailMapper.updateMapByCriteria(map2, crt1);
            // 更新上架任务
            crt3.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
            this.taskInstockDetailMapper.updateMapByCriteria(map2, crt3);
            // 更新复检任务
            crt2.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
            this.taskQcRecheckDetailMapper.updateMapByCriteria(map2, crt2);
            // 更新异常任务
            crt4.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
            this.mapper.updateMapByCriteria(map2, crt4);
        }
        // 更新rcvLineId所对应的数据(收货行)
        excuteUpdateRcvLine(dto, map3, crt5);

    }

    /**
     * 
     * @Description: 执行错误修复(质检节点)
     * @param row
     */
    @Transactional
    public void excuteUpdateQcTask(ExceptionLinesDTO dto, Map<String, Object> map, Map<String, Object> map2,
            Map<String, Object> map3, Criteria crt1, Criteria crt2, Criteria crt3, Criteria crt4, Criteria crt5,
            int row) {
        log.info("开始执行质检错误节点处理---------------------------------------------");
        String nodeTaskId = dto.getNodeTaskId();
        BigDecimal pieceQtyNew = dto.getPieceQtyNew();
//		TaskQcDetail detail = taskQcDetailMapper.findById(nodeTaskId, TaskQcDetail.class);
//		AssertUtils.notNull(detail, "异常出现的节点任务为空!");
        // 包装含量
        BigDecimal conversionRate = dto.getConversionRate();
        // 新的过期时间
        Date expiredDateNew = dto.getExpiredDateNew();
        // 新的生产时间
        Date productionDateNew = dto.getProductionDateNew();
        // 新的qty
        BigDecimal qtyNew = dto.getQtyNew();
        String showExpiredDateNew = dto.getShowExpiredDateNew();
        String showExpiredDateOld = dto.getShowExpiredDateOld();
        String showProductionDateOld = dto.getShowProductionDateOld();
        String showProductionDateNew = dto.getShowProductionDateNew();
        String manufacturerLotNumOld = dto.getManufacturerLotNumOld();
        String manufacturerLotNumNew = dto.getManufacturerLotNumNew();
        BigDecimal pieceQtyOld = dto.getPieceQtyOld();

        if ((!StringUtils.isBlank(showExpiredDateNew) && !showExpiredDateNew.equals(showExpiredDateOld))
                || (!StringUtils.isBlank(showProductionDateNew)
                && !showProductionDateOld.equals(showProductionDateNew))||(!StringUtils.isBlank(manufacturerLotNumNew)
                && !manufacturerLotNumOld.equals(manufacturerLotNumNew))) {
            map.put("status", "1"); // 任务可执行

            // 校验批次是否有库存信息,是否可调整. TODO
            //excuteVaildateBatchHasInstock(dto, row);
            // 修改了批次信息
            if (ObjectUtils.isNotNull(expiredDateNew)) {
                map3.put("batchExpiredDate", expiredDateNew);
            }
            if (ObjectUtils.isNotNull(productionDateNew)) {
                map3.put("batchProductionDate", productionDateNew);
            }
            if (ObjectUtils.isNotNull(showProductionDateNew)) {
                map3.put("showProductionDate", showProductionDateNew);
            }
            if (ObjectUtils.isNotNull(showExpiredDateNew)) {
                map3.put("showExpiredDate", showExpiredDateNew);
            }
            if (ObjectUtils.isNotNull(manufacturerLotNumNew)) {
                map3.put("manufacturerLotNum", manufacturerLotNumNew);
                map.put("manufacturerLotNum", manufacturerLotNumNew);
            }
            map.put("batchId",dto.getBatchIdNew());
            map.put("batchNum",dto.getBatchNumNew());
            map3.put("batchId",dto.getBatchIdNew());
            map3.put("batchNum",dto.getBatchNumNew());
        }

        if (null != pieceQtyNew && pieceQtyOld.compareTo(pieceQtyNew) == 1) {
            // 修改了数量
            map.put("pieceQty", pieceQtyNew);
            map.put("gmtModified", new Date());
            if (BigDecimal.ZERO.compareTo(pieceQtyNew) == 0) {
                // 数量为0
                map.put("qty", BigDecimal.ZERO);
            } else {
                // 不为0
                map.put("status", "1"); // 任务可执行
                if (null == qtyNew) {
                    if (null == conversionRate || conversionRate.compareTo(BigDecimal.ZERO) == 0) {
                        map.put("qty", pieceQtyNew);
                        map.put("conversionRate", 1);
                    } else {
                        map.put("qty", pieceQtyNew.divide(conversionRate, 2, BigDecimal.ROUND_DOWN));
                    }
                } else {
                    map.put("qty", qtyNew);
                }
            }
//			Integer dataVersion = detail.getDataVersion();
//			crt1.setRestriction(
//					Restrictions.eq("dataVersion", dataVersion).and(Restrictions.eq("taskRqcId", nodeTaskId)));
//			long l1 = this.taskQcDetailMapper.updateMapByCriteria(map, crt1);
//			if (l1 <= 0)
//				// 更新失败(有人在操作)
//				throw new BizException(String.format("第[%d]行,异常来源节点的任务(质检)id:[%s]查询的任务执行中,请刷新重试!", row, nodeTaskId));
//
            BigDecimal subtract = pieceQtyOld.subtract(pieceQtyNew);
            map3.put("diffPieceQty", subtract);
//			log.info("结束执行质检错误节点处理---------------------------------------------");
        }
        TaskQcDetail detail = taskQcDetailMapper.findById(nodeTaskId, TaskQcDetail.class);
        AssertUtils.notNull(detail, "异常出现的节点任务为空!");
        Integer dataVersion = detail.getDataVersion();
        Restriction eq = Restrictions.eq("dataVersion", dataVersion);
        Restriction eq2 = Restrictions.eq("taskRqcId", nodeTaskId);
        Restriction eq3 = Restrictions.eq("status", "0"); // 不可执行
        crt1.setRestriction(Restrictions.and(eq, eq2, eq3));
        map.put("dataVersion", dataVersion + 1);
        long l1 = this.taskQcDetailMapper.updateMapByCriteria(map, crt1);
        if (l1 <= 0)
            // 更新失败(有人在操作)
            throw new BizException(String.format("第[%d]行,异常来源节点的任务(质检)id:[%s]查询的任务执行中,请刷新重试!", row, nodeTaskId));
        log.info("结束执行质检错误节点处理---------------------------------------------");

        // 更新所有的rcvlineId所对应的task
        crt1.setRestriction(null);

        //更新双人验收数据
        List<RqcLines> taskRqcId = rqcLinesMapper.findByMap(MapUtils.put("taskRqcId", nodeTaskId).getMap(),RqcLines.class);
        if(taskRqcId.size()>0){
            for (RqcLines rqcLines : taskRqcId) {
                rqcLines.setPieceQty(pieceQtyNew);
                BigDecimal[] bigDecimals = pieceQtyNew.divideAndRemainder(conversionRate);
                rqcLines.setOddCaseQty(bigDecimals[0]);
                rqcLines.setOddPieceQty(bigDecimals[1]);
                rqcLines.setGmtModified(new Date());
                rqcLines.setModifier(userUtils.getUserId());
                rqcLines.setModifierName(userUtils.getUserDTO().getNickname());
                rqcLinesMapper.update(rqcLines);
            }
        }

        // 更新收货行信息表
        // 更新的数据过多,建议关联查询
        excuteUpdateTask(dto, map2, map3, crt1, crt2, crt3, crt4, crt5);

    }
//	/**
//	 * 
//	 * @Description: 执行错误修复(质检节点)
//	 * @param row
//	 */
//	private void excuteUpdateQcTask(ExceptionLinesDTO dto, Map<String, Object> map, Map<String, Object> map2,
//			Map<String, Object> map3, Criteria crt1, Criteria crt2, Criteria crt3, Criteria crt4, Criteria crt5,
//			int row) {
//		String nodeTaskId = dto.getNodeTaskId();
//		BigDecimal pieceQtyNew = dto.getPieceQtyNew();
//		TaskQcDetail detail = taskQcDetailMapper.findById(nodeTaskId, TaskQcDetail.class);
//		AssertUtils.notNull(detail, "异常出现的节点任务为空!");
//		// 包装含量
//		BigDecimal conversionRate = dto.getConversionRate();
//		// 新的批次id
//		String batchIdNew = dto.getBatchIdNew();
//		// 新的批次号
//		String batchNumNew = dto.getBatchNumNew();
//		// 新的过期时间
//		Date expiredDateNew = dto.getExpiredDateNew();
//		// 新的生产时间
//		Date productionDateNew = dto.getProductionDateNew();
//		// 新的批号(生产商)
//		String manufacturerLotNumNew = dto.getManufacturerLotNumNew();
//		// 新的供应商批号
//		String vendorBatchNumNew = dto.getVendorBatchNumNew();
//		// 新的qty
//		BigDecimal qtyNew = dto.getQtyNew();
//		
//		// 更新对应的错误节点任务的数据(乐观锁)
//		map.put("status", 1);
//		Integer dataVersion = detail.getDataVersion();
//		crt1.setRestriction(Restrictions.eq("dataVersion", dataVersion).and(Restrictions.eq("taskRqcId", nodeTaskId)));
//		if (null != pieceQtyNew && BigDecimal.ZERO.compareTo(pieceQtyNew) == -1) {
//			map.put("pieceQty", pieceQtyNew);
//			if (null == qtyNew) {
//				if (null == conversionRate || conversionRate.compareTo(BigDecimal.ZERO) == 0) {
//					map.put("qty", pieceQtyNew);
//					map.put("conversionRate", 1);
//				} else {
//					map.put("qty", pieceQtyNew.divide(conversionRate, 2, BigDecimal.ROUND_DOWN));
//				}
//			} else {
//				map.put("qty", pieceQtyNew);
//			}
//		}
//		long l1 = this.taskQcDetailMapper.updateMapByCriteria(map, crt1);
//		if (l1 <= 0)
//			// 更新失败(有人在操作)
//			throw new BizException(String.format("第[%d]行,异常来源节点的任务(质检)id:[%s]查询的任务执行中,请刷新重试!", row, nodeTaskId));
//		
////		if (ObjectUtils.isNotNull(batchIdNew)) {
////			map2.put("batchId", batchIdNew);
////			map3.put("batchId", batchIdNew);
////		}
////		if (ObjectUtils.isNotNull(batchNumNew)) {
////			map2.put("batchNum", batchNumNew);
////			map3.put("batchNum", batchNumNew);
////		}
//		if (ObjectUtils.isNotNull(expiredDateNew)) {
//			map3.put("batchExpiredDate", expiredDateNew);
//		}
//		if (ObjectUtils.isNotNull(productionDateNew)) {
//			map3.put("batchProductionDate", productionDateNew);
//		}
//		if (ObjectUtils.isNotNull(manufacturerLotNumNew)) {
//			map2.put("manufacturerLotNum", manufacturerLotNumNew);
//			map3.put("manufacturerLotNum", manufacturerLotNumNew);
//		}
//		if (ObjectUtils.isNotNull(vendorBatchNumNew)) {
//			map2.put("vendorBatchNum", vendorBatchNumNew);
//			map3.put("vendorBatchNum", vendorBatchNumNew);
//		}
//		// 更新的数据过多,建议关联查询
//		// 更新所有的rcvlineId所对应的task
//		String rcvLineId = dto.getRcvLineId();
//		
//		// 更新质检任务
//		crt1.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
//		this.taskQcDetailMapper.updateMapByCriteria(map2, crt1);
//		// 更新上架任务
//		crt3.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
//		this.taskInstockDetailMapper.updateMapByCriteria(map2, crt3);
//		
//		// 更新复检任务
//		crt2.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
//		this.taskQcRecheckDetailMapper.updateMapByCriteria(map2, crt2);
//		// 更新异常任务
//		crt4.setRestriction(Restrictions.eq("rcvLineId", rcvLineId));
//		this.mapper.updateMapByCriteria(map2, crt4);
//		
//		// 更新rcvLineId所对应的数据(收货行)
//		excuteUpdateRcvLine(dto, map3, crt5);
//		
//	}

    /**
     * 
     * @Description: 执行收货行的数据修复
     * @param dto
     * @param map3
     * @param crt5
     */
    private void excuteUpdateRcvLine(ExceptionLinesDTO dto, Map<String, Object> map3, Criteria crt5) {
        if (ObjectUtils.isNull(map3)) {
            return;
        }
        String nodeType = dto.getNodeType();
        String rcvLineId = dto.getRcvLineId();
        BigDecimal pieceQtyNew = dto.getPieceQtyNew();
        BigDecimal pieceQtyOld = dto.getPieceQtyOld();
        Date now = new Date();
        long time = now.getTime();
        while (true) {
            // 使用自旋乐观锁(数据库实现)
            Date now2 = new Date();
            long time2 = now2.getTime();
            // 最多6秒
            if ((time2 - time) / 1000 > 5)
                throw new BizException("更新收货明细失败!请刷新重试!");

            RcvLines rcvLines = this.rcvLinesMapper.findById(rcvLineId, RcvLines.class);
            BigDecimal freeQty = rcvLines.getFreeQty(); // freeQty+pieceQty == all ? or pieceQty == all
            if (freeQty == null)
                freeQty = BigDecimal.ZERO;

            BigDecimal conversionRate2 = rcvLines.getConversionRate();
            if (conversionRate2 == null || BigDecimal.ZERO.compareTo(conversionRate2) == 0)
                conversionRate2 = BigDecimal.ONE;

            BigDecimal pieceQty = rcvLines.getPieceQty();
//			if (null != pieceQtyNew && BigDecimal.ZERO.compareTo(pieceQtyNew) == -1) {
//				BigDecimal subtract = pieceQtyOld.subtract(pieceQtyNew);
//				BigDecimal subtract2 = pieceQty.subtract(subtract);
//				BigDecimal add = subtract2.add(freeQty);
//				BigDecimal divide = add.divide(conversionRate2, 2, BigDecimal.ROUND_DOWN);
//				BigDecimal divide2 = add.divide(conversionRate2, RoundingMode.FLOOR);
//				BigDecimal subtract3 = add.subtract(divide2.multiply(conversionRate2));
            if (map3.containsKey("diffPieceQty")
                    && BigDecimal.ZERO.compareTo((BigDecimal) map3.get("diffPieceQty")) == -1) {
                BigDecimal diffPieceQty = (BigDecimal) map3.get("diffPieceQty");
                BigDecimal add = pieceQty.subtract(diffPieceQty);
                // 为负数时的处理
                if (BigDecimal.ZERO.compareTo(add) == 1) {
                    // 是否需要抛错? TODO
                    add = BigDecimal.ZERO;
                }
                BigDecimal divide = add.divide(conversionRate2, 4, BigDecimal.ROUND_DOWN);
                BigDecimal caseQty = add.divide(conversionRate2, 0, RoundingMode.DOWN); // 整件
                BigDecimal multiply = caseQty.multiply(conversionRate2);
                BigDecimal oddPieceQty = add.subtract(multiply); // 零散

                map3.put("qty", divide);
                map3.put("pieceQty", add);
                map3.put("oddCaseQty", caseQty);
                map3.put("oddPieceQty", oddPieceQty);
            }

            Integer dataVersion2 = rcvLines.getDataVersion();
            dataVersion2 = dataVersion2 == null ? 1 : dataVersion2;
            if (map3.containsKey("diffPieceQty")) {
                map3.remove("diffPieceQty");
            }
            map3.put("dataVersion", dataVersion2 + 1);
            crt5.setRestriction(
                    Restrictions.eq("dataVersion", dataVersion2).and(Restrictions.eq("rcvLineId", rcvLineId)));
            long l = this.rcvLinesMapper.updateMapByCriteria(map3, crt5);
            if (l > 0) {
                return;
//				// 判断此收货单是否全部上架完毕,回传erp
//				BigDecimal itemQty = (BigDecimal) map3.get("pieceQty");
//				// 不管是那个节点只要有上架的数据,都得判断回不回传
////				if (BizConstant.WMS_EXCEPTION_NODE_INSTOCK.equals(nodeType)) { 
//				// 若是收货行数量不是0,并且是上架节点异常,需要判断该收货单是否回传erp ->错误观点
//				String rcvHeaderId = dto.getRcvHeaderId();
//				List<RcvInstockLines> findByMap = this.instockMapper
//						.findByMap(MapUtils.put("rcvHeaderId", rcvHeaderId).getMap(), RcvInstockLines.class);
//				if (ObjectUtils.isNull(findByMap)) {
//					return;
//				}
//				log.info("收货单id" + rcvHeaderId + "异常处理执行上架回传逻辑---------------------------------------");
//				this.instockService.excuteCallBackErp(findByMap, callSleepTimes * 1); // 2分钟
////				}
            }
        }

    }

    private void updateTaskStatus(ExceptionLinesDTO exceptionLinesDTO, UserDTO userDTO, Date now, int row) {
        String taskId = exceptionLinesDTO.getTaskExceptionId();
        AssertUtils.isNotBlank(taskId, String.format("第[%d]行,异常任务执行的id(taskExceptionId)为空!", row));

        // 数据库乐观锁控制并发
        TaskExceptionDetail model = this.taskMapper.findById(taskId, TaskExceptionDetail.class);
        String nodeTaskId = model.getNodeTaskId();
        exceptionLinesDTO.setNodeTaskId(nodeTaskId);
        AssertUtils.notNull(model, String.format("第[%d]行,异常任务id:[%s]查询的任务为空!", row, taskId));
        String status = model.getStatus();
        if (!"1".equals(status))
            throw new BizException(String.format("第[%d]行,异常任务id:[%s]查询的任务已经执行,请刷新重试!", row, taskId));
        Integer dataVersion = model.getDataVersion();
        Criteria criteria = new Criteria(TaskExceptionDetail.class);
        criteria.restrictionBuilder().eq("dataVersion", dataVersion).eq("taskExceptionId", taskId);
        criteria.buildRestriction();

        long count = this.taskMapper.updateMapByCriteria(
                MapUtils.put("dataVersion", dataVersion + 1).put("status", "0").getMap(), criteria);
        if (count <= 0)
            // 更新失败,说明有人在操作
            throw new BizException(String.format("第[%d]行,异常任务id:[%s]查询的任务执行中,请刷新重试!", row, taskId));

    }

    private void buildDefaultField(ExceptionLinesDTO dto, Date now, UserDTO userDTO) {
        // 构建数据默认字段
        Date executorDate = dto.getExecutorDate();
        String executorUser = dto.getExecutorUser();
        String status = dto.getStatus();
        if (ObjectUtils.isNull(executorDate))
            dto.setExecutorDate(new Date());
        if (ObjectUtils.isNull(executorUser))
            dto.setExecutorUser(userDTO.getUsername());
        if (ObjectUtils.isNull(status))
            dto.setStatus("0"); // 直接就是已处理的,后期根据需求变化

    }

    @Override
    public Object add(ExceptionLinesDTO exceptionLinesDTO) {
        // TODO vaildate
        UserDTO userDTO = userUtils.getUserDTO();
        ExceptionLines exceptionLines = new ExceptionLines();
        BeanUtils.copyProperties(exceptionLinesDTO, exceptionLines);
        this.vaildateModel(exceptionLines, false, userDTO);
        this.buildField(exceptionLines, false, userDTO);
        this.mapper.save(exceptionLines);
        return "";
    }

    @Override
    public Object edit(String pkId, ExceptionLinesDTO exceptionLinesDTO) {
        // TODO
        UserDTO userDTO = userUtils.getUserDTO();
        ExceptionLines exceptionLines = new ExceptionLines();
        BeanUtils.copyProperties(exceptionLinesDTO, exceptionLines);
        this.vaildateModel(exceptionLines, true, userDTO);
        this.buildField(exceptionLines, true, userDTO);
        this.mapper.updateWithValidate(exceptionLines,
                p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
        return "";
    }

    @Override
    @Transactional
    public Object delIds(List<String> pkIdList) {
        // TODO
        pkIdList.stream().filter(p -> canEdit(p)).forEach(p -> this.mapper.deleteById(p, ExceptionLines.class));
        return "";
    }

    @Override
    public Object deletePkId(String pkId) {
        // TODO
        if (canEdit(pkId))
            throw new BizException("can not del");
        this.mapper.deleteById(pkId, ExceptionLines.class);
        return "";
    }

    @Override
    public Page<ExceptionLinesDTO> findList(ExceptionLinesDTO exceptionLinesDTO, PageParam pageParam) {
        Criteria criteria = Criteria.forClass(ExceptionLines.class);
        Integer pageNum = null;
        Integer pageSize = null;
        Restriction r = null;
        if (pageParam == null) {
            pageNum = PageParam.DEFAULT_PAGE_NUM;
            pageSize = PageParam.DEFAULT_PAGE_SIZE;
        } else {
            pageNum = pageParam.getPageNum();
            pageSize = pageParam.getPageSize();
            ExceptionLinesDTO condition = exceptionLinesDTO;
            r = buildCondition(condition);
        }
        if (pageNum == null || pageNum == 0) {
            pageNum = PageParam.DEFAULT_PAGE_NUM;
        }
        if (pageSize == null || pageSize == 0) {
            pageSize = PageParam.DEFAULT_PAGE_SIZE;
        }
        criteria.setRestriction(r);
        Order order = Order.newInstance().desc("gmtModified");
        criteria.setOrder(order);
        PageUtils.startPage(pageNum, pageSize);
        List<ExceptionLines> list = this.mapper.findByCriteria(criteria);
        List<ExceptionLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
            ExceptionLinesDTO target = new ExceptionLinesDTO();
            BeanUtils.copyProperties(p, target);
            return target;
        }).collect(Collectors.toList());
        Page<ExceptionLines> page = PageUtils.getPage(list);
        Page<ExceptionLinesDTO> page2 = new Page<>();
        page2.setStartRow(page.getStartRow());
        page2.setEndRow(page.getEndRow());
        page2.setPageCount(page.getPageCount());
        page2.setPageNum(page.getPageNum());
        page2.setPageSize(page.getPageSize());
        page2.setTotalCount(page.getTotalCount());
        page2.setList(collect);
        return page2;
    }

    @Override
    @Transactional
    public Object batchAdd(List<ExceptionLinesDTO> exceptionLinesDTOList) {
        // TODO
        UserDTO userDTO = userUtils.getUserDTO();
        for (ExceptionLinesDTO exceptionLinesDTO : exceptionLinesDTOList) {
            ExceptionLines exceptionLines = new ExceptionLines();
            BeanUtils.copyProperties(exceptionLinesDTO, exceptionLines);
            this.vaildateModel(exceptionLines, false, userDTO);
            this.buildField(exceptionLines, false, userDTO);
            this.mapper.save(exceptionLines);
        }
        return "";
    }

    @Override
    @Transactional
    public Object batchEdit(List<ExceptionLinesDTO> exceptionLinesDTOList) {
        // TODO
        UserDTO userDTO = userUtils.getUserDTO();
        for (ExceptionLinesDTO exceptionLinesDTO : exceptionLinesDTOList) {
            ExceptionLines exceptionLines = new ExceptionLines();
            BeanUtils.copyProperties(exceptionLinesDTO, exceptionLines);
            this.vaildateModel(exceptionLines, true, userDTO);
            this.buildField(exceptionLines, true, userDTO);
            this.mapper.updateWithValidate(exceptionLines,
                    p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
        }
        return "";
    }

    @Override
    public List<ExceptionLinesDTO> findAll(ExceptionLinesDTO exceptionLinesDTO) {
        // TODO
        Criteria criteria = Criteria.forClass(ExceptionLines.class);
        ExceptionLinesDTO condition = exceptionLinesDTO;
        Restriction r = buildCondition(condition);
        criteria.setRestriction(r);
        Order order = Order.newInstance().desc("gmtModified");
        criteria.setOrder(order);
        List<ExceptionLines> list = this.mapper.findByCriteria(criteria);
        List<ExceptionLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
            ExceptionLinesDTO target = new ExceptionLinesDTO();
            BeanUtils.copyProperties(p, target);
            return target;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    public ExceptionLinesDTO findByPkId(String pkId) {
        // TODO
        ExceptionLines exceptionLines = this.findById(pkId);
        AssertUtils.notNull(exceptionLines, "model empty!");
        ExceptionLinesDTO exceptionLinesDTO = new ExceptionLinesDTO();
        BeanUtils.copyProperties(exceptionLines, exceptionLinesDTO);
        return exceptionLinesDTO;
    }

    private ExceptionLines findById(String id) {
        return this.mapper.findById(id, ExceptionLines.class);
    }

    private void vaildateModel(ExceptionLines exceptionLines, Boolean editFlag, UserDTO userDTO) {
        if (!editFlag) {
            // TODO add
        } else {
            // TODO
        }
    }

    private void buildField(ExceptionLines exceptionLines, Boolean editFlag, UserDTO userDTO) {
        if (!editFlag) {
            // TODO add
        } else {
            // TODO edit
        }
        vaildateModelRepeated(exceptionLines, editFlag, userDTO);
    }

    private void vaildateModelRepeated(ExceptionLines exceptionLines, Boolean editFlag, UserDTO userDTO) {
        if (!editFlag) {
            // TODO add
        } else {
            // TODO
        }
    }

    private boolean canEdit(String pkId) {
        boolean flag = true;
        ExceptionLines exceptionLines = this.findById(pkId);
        AssertUtils.notNull(exceptionLines, "model empty!");
        // TODO
        if (true)
            flag = false;
        return flag;
    }

    private Restriction buildCondition(ExceptionLinesDTO exceptionLinesDTO) {
        // TODO
        return null;
    }

    @Override
    @Transactional
    public Object cancel(List<ExceptionLinesDTO> exceptionLineList) {
        UserDTO userDTO = userUtils.getUserDTO();
        Date now = new Date();
        int row = 0;
        List<String> rqcTaskIds = new ArrayList<>();
        List<String> instockTaskIds = new ArrayList<>();
        for (ExceptionLinesDTO exceptionLinesDTO : exceptionLineList) {
            row++;
//			String taskExceptionId = exceptionLinesDTO.getTaskExceptionId();
            this.updateTaskStatus(exceptionLinesDTO, userDTO, now, row);
            String nodeType = exceptionLinesDTO.getNodeType();
            String nodeTaskId = exceptionLinesDTO.getNodeTaskId().trim();
            if (BizConstant.WMS_EXCEPTION_NODE_RCV.replace("\"", "").equals(nodeType.trim())) {
                // 预留处理
            }
            if (BizConstant.WMS_EXCEPTION_NODE_RQC.replace("\"", "").equals(nodeType.trim())) {
                // 质检节点异常处理
                rqcTaskIds.add(nodeTaskId);
            }
            if (BizConstant.WMS_EXCEPTION_NODE_RERQC.replace("\"", "").equals(nodeType.trim())) {
                // 复检节点异常处理
            }
            if (BizConstant.WMS_EXCEPTION_NODE_INSTOCK.replace("\"", "").equals(nodeType.trim())) {
                // 上架节点异常处理
                instockTaskIds.add(nodeTaskId);
            }
        }
        Map<String, Object> map = new HashMap<>();
        map.put("status", "1");
        map.put("gmtModified", now);
        if (ObjectUtils.isNotNull(rqcTaskIds)) {
            Criteria crt1 = new Criteria(TaskQcDetail.class);
            crt1.setRestriction(Restrictions.in("taskRqcId", rqcTaskIds.toArray(new String[rqcTaskIds.size()])));
            excuteUpdateQcTask(crt1, map);
        }
        if (ObjectUtils.isNotNull(instockTaskIds)) {
            Criteria crt2 = new Criteria(TaskInstockDetail.class);
            crt2.setRestriction(
                    Restrictions.in("taskInboundId", rqcTaskIds.toArray(new String[instockTaskIds.size()])));
            excuteUpdateInstockTask(crt2, map);
        }
        return true;
    }

    private void excuteUpdateInstockTask(Criteria crt2, Map<String, Object> map) {
        this.taskInstockDetailMapper.updateMapByCriteria(map, crt2);
    }

    private void excuteUpdateQcTask(Criteria crt1, Map<String, Object> map) {
        this.taskQcDetailMapper.updateMapByCriteria(map, crt1);
    }

    // 执行批次驳回
    @Override
    @Transactional
    @TxTransaction(isStart = true)
    public Object rejectLotNo(List<ExceptionLinesDTO> exceptionLineList) {
        log.info("开始执行异常批次驳回逻辑--------------------------------");
        UserDTO userDTO = userUtils.getUserDTO();
        Date now = new Date();
        int row = 0;
        Set<String> batchIdSet = exceptionLineList.stream().map(ExceptionLinesDTO::getBatchIdOld)
                .collect(Collectors.toSet());
        String warehouseId = exceptionLineList.get(0).getWarehouseId();
        if (ObjectUtils.isNull(batchIdSet)) {
            throw new BizException("驳回的批次数据为空!请检查重试!");
        }
        try {
            excuteDelLotInfo(warehouseId, batchIdSet); // 需要抛错
        } catch (Exception e) {
            log.info("执行异常批次驳回远程删除未占用库存失败!原因->{}", e);
            throw new BizException("商品批号有库存无法驳回!请进行数量调整!");
//			throw new BizException("商品批号已有库存信息,无法进行批号驳回操作,若需要修改批号,请进行批号调整,若调整数量,请进行数量调整.错误原因->" + e.getMessage());
        }
//		Map<String, Boolean> result = excuteVaildateHasInstock(warehouseId, batchIdSet);
        List<String> preInstockLineId = new ArrayList<>();
        for (ExceptionLinesDTO exceptionLinesDTO : exceptionLineList) {
            row++;

//			if (!ObjectUtils.isNull(result)) {
//				Boolean flag = result.get(exceptionLinesDTO.getBatchIdOld());
//				if (flag) {
//					throw new BizException(String.format("第[%d]行,批号[%s]已有库存信息,无法驳回,若要修改,请联系相关人员去批次调整中进行修改!", row,
//							exceptionLinesDTO.getManufacturerLotNumOld()));
//				}
//			}
//			String taskExceptionId = exceptionLinesDTO.getTaskExceptionId();

//			this.updateTaskStatus(exceptionLinesDTO, userDTO, now, row);
            String nodeTaskId = exceptionLinesDTO.getNodeTaskId();
            String nodeType = exceptionLinesDTO.getNodeType();

//			// 若是验收批号驳回,需要更新验收任务,收货行减去
//			if (BizConstant.WMS_EXCEPTION_NODE_RQC.equals(nodeType)) {
//				TaskQcDetailDTO qcTask = taskQcDetailMapper.findByPKId(nodeTaskId);
//				String rcvLineId = qcTask.getRcvLineId();
//				BigDecimal pieceQty = qcTask.getPieceQty();
//				if (qcTask != null) {
//					taskQcDetailMapper.updateMapById(nodeTaskId,
//							MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(),
//							TaskQcDetail.class);
//					RcvLinesDTO rcvLine = rcvLinesMapper.findByPkId(rcvLineId);
//					BigDecimal pieceQty2 = rcvLine.getPieceQty();
//					BigDecimal conversionRate = rcvLine.getConversionRate();
//					// 计算qty,保证准确性
//					if (pieceQty == null)
//						pieceQty = BigDecimal.ZERO;
//					if (pieceQty2 == null)
//						pieceQty2 = BigDecimal.ZERO;
//					if (conversionRate == null || BigDecimal.ZERO.compareTo(conversionRate) == 0)
//						conversionRate = BigDecimal.ONE;
//					BigDecimal subtract = pieceQty2.subtract(pieceQty);
//
//					BigDecimal caseQty = subtract.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
//					BigDecimal multiply = caseQty.multiply(conversionRate);
//					BigDecimal oddPieceQty = subtract.subtract(multiply); // 零散
//					BigDecimal qty = pieceQty.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
//					rcvLinesMapper.updateMapById(rcvLineId,
//							MapUtils.put("segment1", "1").put("qty", qty).put("pieceQty", subtract)
//									.put("oddCaseQty", caseQty).put("oddPieceQty", oddPieceQty).getMap(),
//							RcvLines.class);
//				}
//			}
//			// 若是复检批号驳回,需要更新复检任务,需更新验收行,验收任务,抽检明细,收货明细
//			if (BizConstant.WMS_EXCEPTION_NODE_RERQC.equals(nodeType)) {
//				TaskQcRecheckDetail taskReQc = taskQcRecheckDetailMapper.findById(nodeTaskId,
//						TaskQcRecheckDetail.class);
//				if (taskReQc != null) {
//					String rcvLineId = taskReQc.getRcvLineId();
//					BigDecimal pieceQty = taskReQc.getPieceQty();
//					Integer refType = taskReQc.getRefType();
////					 SEGMENT1 = '1', PIECE_QTY=0,STATUS = '0'
//					// 更新复检任务
//					taskQcRecheckDetailMapper.updateMapById(nodeTaskId,
//							MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(),
//							TaskQcRecheckDetail.class);
//
//					// 更新验收行
//					if (refType != null && 1 == refType) {
//						String rqcLineId = taskReQc.getRefLineId();
//						RqcLines rqcLine = rqcLinesMapper.findById(rqcLineId, RqcLines.class);
//						if (rqcLine != null) {
//							BigDecimal pieceQty2 = rqcLine.getPieceQty();
//							BigDecimal conversionRate = rqcLine.getConversionRate();
//							// 计算qty,保证准确性
//							if (pieceQty == null)
//								pieceQty = BigDecimal.ZERO;
//							if (pieceQty2 == null)
//								pieceQty2 = BigDecimal.ZERO;
//							if (conversionRate == null || BigDecimal.ZERO.compareTo(conversionRate) == 0)
//								conversionRate = BigDecimal.ONE;
//							BigDecimal subtract = pieceQty2.subtract(pieceQty);
//
//							BigDecimal caseQty = subtract.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
//							BigDecimal multiply = caseQty.multiply(conversionRate);
//							BigDecimal oddPieceQty = subtract.subtract(multiply); // 零散
//							BigDecimal qty = pieceQty.divide(conversionRate, 4, RoundingMode.DOWN); // 包装总量
////							PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0
//							rqcLinesMapper.updateMapById(rqcLineId, MapUtils.put("pieceQty", subtract)
//									.put("oddCaseQty", caseQty).put("oddPieceQty", oddPieceQty).getMap(),
//									RqcLines.class);
//
//							// 更新验收任务
//							String taskRqcId = rqcLine.getTaskRqcId();
//							taskQcDetailMapper.updateMapById(taskRqcId, MapUtils.put("segment1", "1").put("qty", qty)
//									.put("pieceQty", subtract).put("status", "0").getMap(), TaskQcDetail.class);
//
//							// 更新抽检行
//							Criteria crt11 = Criteria.forClass(WmsInRqcSample.class);
//							crt11.setRestriction(Restrictions.eq("taskRqcId", taskRqcId));
//							List<WmsInRqcSample> rqcSamples = rqcSampleMapper.findByCriteria(crt11);
//							if (!ObjectUtils.isNull(rqcSamples) && !ObjectUtils.isNull(rqcSamples.get(0))) {
//								WmsInRqcSample rqcSample = rqcSamples.get(0);
//								BigDecimal pieceQty3 = rqcSample.getPieceQty();
//								pieceQty3 = pieceQty3.subtract(pieceQty);
//
//								rqcSample.setPieceQty(pieceQty3);
//								BigDecimal caseQty2 = pieceQty3.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
//								BigDecimal multiply2 = caseQty2.multiply(conversionRate);
//								BigDecimal oddPieceQty2 = pieceQty3.subtract(multiply2); // 零散
//
//								rqcSample.setOddCaseQty(caseQty2);
//								rqcSample.setOddPieceQty(oddPieceQty2);
//								BigDecimal qcOddPieceQty = rqcSample.getQcOddPieceQty();
//								BigDecimal qcOddCaseQty = rqcSample.getQcOddCaseQty();
//								BigDecimal add = qcOddCaseQty.multiply(conversionRate).add(qcOddPieceQty);
//								if (add.compareTo(pieceQty2) == 1) {
//									rqcSample.setQcOddCaseQty(caseQty2);
//									rqcSample.setQcOddPieceQty(oddPieceQty2);
//								}
//								BigDecimal qcOddCaseActQty = rqcSample.getQcOddCaseActQty();
//								BigDecimal qcOddPieceActQty = rqcSample.getQcOddPieceActQty();
//								BigDecimal add2 = qcOddCaseActQty.multiply(conversionRate).add(qcOddPieceActQty);
//								if (add2.compareTo(pieceQty2) == 1) {
//									rqcSample.setQcOddCaseActQty(caseQty2);
//									rqcSample.setQcOddPieceActQty(oddPieceQty2);
//								}
//								rqcSampleMapper.update(rqcSample);
//							}
//							// 更新收货行
//							rcvLinesMapper.updateMapById(rcvLineId,
//									MapUtils.put("segment1", "1").put("qty", qty).put("pieceQty", subtract)
//											.put("oddCaseQty", caseQty).put("oddPieceQty", oddPieceQty).getMap(),
//									RcvLines.class);
//						}
//					}
//				}
//			}
//			// 若是上架批号驳回,需要更新上架任务,更新复检行,复检任务,验收行,验收任务,抽检明细,收货明细
//			if (BizConstant.WMS_EXCEPTION_NODE_INSTOCK.equals(nodeType)) {
//				TaskInstockDetail taskInstockDetail = taskInstockDetailMapper.findById(nodeTaskId,
//						TaskInstockDetail.class);
//				if (taskInstockDetail != null) {
//					String rcvLineId = taskInstockDetail.getRcvLineId();
//					BigDecimal pieceQty = taskInstockDetail.getPieceQty();
//					// 更新上架任务
////					 SEGMENT1 = '1',QTY = 0,PIECE_QTY=0,STATUS = '0'
//					taskInstockDetailMapper.updateMapById(nodeTaskId,
//							MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(),
//							TaskInstockDetail.class);
//
//				}
//			}

            excuteReject(exceptionLinesDTO.getBatchIdOld()); // 其实可批量删,传递批次集合数据

//			// 判断回传 保存明细的时候会判断回传
//			// 判断此收货单是否全部上架完毕,回传erp
//			if (nodeType.equals(BizConstant.WMS_EXCEPTION_NODE_INSTOCK)) {
//				// 只有上架节点异常才会判断
//				String rcvHeaderId = exceptionLinesDTO.getRcvHeaderId();
//				List<RcvInstockLines> findByMap = this.instockMapper.findByMap(
//						(Map<String, Object>) MapUtils.put("rcvHeaderId", rcvHeaderId).getMap(), RcvInstockLines.class);
//				if (!ObjectUtils.isNull(findByMap)) {
//					this.instockService.excuteCallBackErp(findByMap, false);
//				}
//			}

            // 删除质检后的预占数据
//			String nodeType = exceptionLinesDTO.getNodeType();
//			String nodeTaskId = exceptionLinesDTO.getNodeTaskId();
            if (nodeType.equals("40")) {
                // 来源上架节点需要清理预占
                preInstockLineId.add(nodeTaskId);
            }

        }

        // 清理预占
        if (!ObjectUtils.isNull(preInstockLineId)) {
            log.info("执行异常批次驳回清理预占--------------------------------");
            InvStockCancel c = new InvStockCancel();
            c.setLineBillIds(preInstockLineId.toArray(new String[preInstockLineId.size()]));
            try {
                RestMessage inCancel = baseInventoryRemoteCaller.inCancel(c);
                if (inCancel != null && !inCancel.isSuccess()) {
                    log.info("异常远程调用清理预占,返回结果->", inCancel.getMessage() + inCancel.getData());
                }
            } catch (Exception e) {
                log.info("异常处理调用清理入库预占异常,原因{}", e);
            }
        }

        log.info("结束执行异常批次驳回逻辑--------------------------------");
        return true;
    }

//	private void excuteRejectByRqcNode(String batchId, String taskId, BigDecimal pieceQty, String rcvLineId) {
//		this.mapper.rejectByRqcNode(batchId, taskId, pieceQty, rcvLineId);
//
//	}

    private void excuteDelLotInfo(String warehouseId, Set<String> batchIdSet) {
        BatchExistsDelVO delVo = new BatchExistsDelVO();
        delVo.setBatchIds(batchIdSet.toArray(new String[batchIdSet.size()]));
        delVo.setWarehouseId(warehouseId);

        log.info("删除无库存的批次信息.-----------------------参数->" + delVo.toString());
        RestMessage deleteBatchNumbersNotExists = baseInventoryRemoteCaller.deleteBatchNumbersNotExists(delVo);
        if (deleteBatchNumbersNotExists != null) {
            boolean success = deleteBatchNumbersNotExists.isSuccess();
            if (!success) {
                Object data = deleteBatchNumbersNotExists.getData();
                if (data != null) {
                    throw new BizException(deleteBatchNumbersNotExists.getMessage() + data.toString());
                } else {
                    throw new BizException(deleteBatchNumbersNotExists.getMessage());
                }

            }
        }
    }

    private Map<String, Boolean> excuteVaildateHasInstock(String warehouseId, Set<String> batchIdSet) {
        RestMessage<List<BatchExistsVO>> batchNumbersExists = baseInventoryRemoteCaller
                .getBatchNumbersExists(warehouseId, batchIdSet.toArray(new String[batchIdSet.size()]));
        List<BatchExistsVO> data = null;
        if (batchNumbersExists != null) {
            boolean success = batchNumbersExists.isSuccess();
            if (success) {
                data = batchNumbersExists.getData();
            } else {
                throw new BizException(batchNumbersExists.getMessage() + batchNumbersExists.getData().toString());
            }
        }
        Map<String, Boolean> collect = null;
        if (!ObjectUtils.isNull(data)) {
            collect = data.stream().collect(
                    Collectors.toMap(BatchExistsVO::getBatchId, BatchExistsVO::isExists, (key1, key2) -> key2));
        }
        return collect;
    }

    private void excuteReject(String batchId) {
        // 为了支持mysql手动实现
//		UPDATE WMS_IN_RCV_LINES set SEGMENT1 = '1',QTY = 0,PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0 WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_TASK_QC_DETAIL set SEGMENT1 = '1',QTY = 0,PIECE_QTY=0,STATUS = '0' WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_RQC_LINES set PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0 WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_RQC_SAMPLE set PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0 WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_TASK_QC_RECHECK_DETAIL set SEGMENT1 = '1', PIECE_QTY=0,STATUS = '0' WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_RQC_RE_LINES set PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0 WHERE BATCH_ID = #{batchId};
//		UPDATE WMS_IN_TASK_INSTOCK_DETAIL set  SEGMENT1 = '1',QTY = 0,PIECE_QTY=0,STATUS = '0' WHERE BATCH_ID = #{batchId};
//		<!-- UPDATE WMS_IN_RCV_INSTOCK_LINES set SEGMENT1 = '1',PIECE_QTY=0,ODD_CASE_QTY=0,ODD_PIECE_QTY = 0 WHERE BATCH_ID = #{batchId}; -->
//		UPDATE WMS_IN_TASK_REJECTED_DETAIL set SEGMENT1 = '1',QTY = 0,PIECE_QTY=0,STATUS = '0' WHERE BATCH_ID = #{batchId};
        // TODO
        try {
            this.mapper.rejectBatch(batchId);
        } catch (Exception e) {
            // 若是删除失败,说明是mysql版本
            Restriction eq = Restrictions.eq("batchId", batchId);
            Criteria crt1 = Criteria.forClass(RcvLines.class);
            crt1.setRestriction(eq);
            this.rcvLinesMapper.updateMapByCriteria(MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0)
                    .put("oddCaseQty", 0).put("oddPieceQty", 0).getMap(), crt1);

            Criteria crt2 = Criteria.forClass(TaskQcDetail.class);
            crt2.setRestriction(eq);
            this.taskQcDetailMapper.updateMapByCriteria(
                    MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(), crt2);

            Criteria crt3 = Criteria.forClass(RqcLines.class);
            crt3.setRestriction(eq);
            this.rqcLinesMapper.updateMapByCriteria(
                    MapUtils.put("pieceQty", 0).put("oddCaseQty", 0).put("oddPieceQty", 0).getMap(), crt3);

            Criteria crt4 = Criteria.forClass(WmsInRqcSample.class);
            crt4.setRestriction(eq);
            this.rqcSampleMapper.updateMapByCriteria(
                    MapUtils.put("pieceQty", 0).put("oddCaseQty", 0).put("oddPieceQty", 0).getMap(), crt4);

            Criteria crt5 = Criteria.forClass(TaskQcRecheckDetail.class);
            crt5.setRestriction(eq);
            this.taskQcRecheckDetailMapper.updateMapByCriteria(
                    MapUtils.put("segment1", "1").put("pieceQty", 0).put("status", "0").getMap(), crt5);

            Criteria crt6 = Criteria.forClass(RqcReLines.class);
            crt6.setRestriction(eq);
            this.rqcReLinesMapper.updateMapByCriteria(
                    MapUtils.put("pieceQty", 0).put("oddCaseQty", 0).put("oddPieceQty", 0).getMap(), crt6);

            Criteria crt7 = Criteria.forClass(TaskInstockDetail.class);
            crt7.setRestriction(eq);
            this.taskInstockDetailMapper.updateMapByCriteria(
                    MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(), crt7);

            Criteria crt8 = Criteria.forClass(TaskRejectedDetail.class);
            crt8.setRestriction(eq);
//            this.taskRejectedDetailMapper.updateMapByCriteria(
//                    MapUtils.put("segment1", "1").put("qty", 0).put("pieceQty", 0).put("status", "0").getMap(), crt8);

        }
    }

    @Override
    public Object hasInstock(String batchId, String warehouseId) {
        Set<String> set = new HashSet<>();
        set.add(batchId);
        return excuteVaildateHasInstock(warehouseId, set);
    }

}
