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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import com.codingapi.tx.annotation.TxTransaction;
import com.esotericsoftware.minlog.Log;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.prolog.common.util.DateUtils;
import com.prolog.cs.basic.common.model.BaseBizFile;
import com.prolog.cs.basic.common.model.BaseCommonDict;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.warehouse.model.vo.ContainerQueryVO;
import com.prolog.cs.basic.warehouse.model.vo.WarehouseAreaQueryVO;
import com.prolog.cs.biz.inbound.constant.BizConstant;
import com.prolog.cs.biz.inbound.dao.SupervisionCodeMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesPicMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesProfilesMapper;
import com.prolog.cs.biz.inbound.dto.CargoChangeIn;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.RcvCommonLine;
import com.prolog.cs.biz.inbound.dto.rcv.RcvHeadersDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvLinesDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvLinesPicDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvLinesProfilesDTO;
import com.prolog.cs.biz.inbound.model.SupervisionCode;
import com.prolog.cs.biz.inbound.model.rcv.RcvLines;
import com.prolog.cs.biz.inbound.model.rcv.RcvLinesPic;
import com.prolog.cs.biz.inbound.remote.*;
import com.prolog.cs.biz.inbound.remote.dto.OmsAsnBillDQueryVO;
import com.prolog.cs.biz.inbound.service.OmsAsnBillDService;
import com.prolog.cs.biz.inbound.service.impl.AutoRqcHandler;
import com.prolog.cs.biz.inbound.service.impl.BaseServiceImpl;
import com.prolog.cs.biz.inbound.service.impl.processor.Helper.TaskHelper;
import com.prolog.cs.biz.inbound.service.impl.processor.enums.ConclusionEnum;
import com.prolog.cs.biz.inbound.service.impl.processor.enums.RcvTypeStrategyEnum;
import com.prolog.cs.biz.inbound.service.impl.processor.enums.RqcStrategyEnum;
import com.prolog.cs.biz.inbound.service.impl.processor.factory.RcvSubjectFactory;
import com.prolog.cs.biz.inbound.service.impl.processor.factory.RcvSubjectFactoryS1Impl;
import com.prolog.cs.biz.inbound.service.impl.processor.handler.TaskHandler;
import com.prolog.cs.biz.inbound.service.impl.strategy.WhAreaCategoryContext;
import com.prolog.cs.biz.inbound.service.rcv.RcvLinesProfilesService;
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.RcvLineLotInfo;
import com.prolog.cs.biz.inbound.vo.RcvLinesQueryVO;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.common.search.SearchApi;
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.exception.ParameterException;
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.*;
import com.prolog.upcloud.base.inventory.vo.InvStockBatchNumber;
import com.prolog.upcloud.base.inventory.vo.InvStockBatchNumberResult;
import com.prolog.upcloud.base.inventory.vo.InvStockBatchNumberUpdate;
import com.prolog.upcloud.base.strategy.common.StrategyCategoryEnum;
import com.prolog.upcloud.base.strategy.domain.core.Strategy;
import com.prolog.upcloud.base.strategy.domain.exception.StrategyExecuteException;
import com.prolog.upcloud.base.strategy.dto.StrategyDTO;
import org.apache.commons.collections4.map.HashedMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
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.time.temporal.ChronoUnit;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;

@Service
public class RcvLinesServiceImpl extends BaseServiceImpl<RcvLines> implements RcvLinesService {

    @Resource
    private RcvLinesMapper mapper;

    @Resource
    private UserUtils userUtils;

    @Resource
    private RcvLinesProfilesService rcvLinesProfilesService;

    @Resource
    private TaskHelper taskHelper;

    @Resource
    @Qualifier("rcvTaskHandler")
    private TaskHandler handler;

    @Resource
    private Validator validator;

    @Value("${prolog.wms.expiredDays:90}")
    private long expiredDays;

    @Resource
    private BaseWmsWarehouseCaller baseWmsWarehouseCaller;

    @Resource
    private CommonCaller commonCaller;

    @Resource
    private OmsAsnBillDService omsAsnBillHService;

    @Resource
    private BaseInventoryRemoteCaller baseInventoryRemoteCaller;

    @Resource
    private AutoRqcHandler autoRqcHandler;

    @Resource
    private RcvLinesPicMapper rcvLinesPicMapper;

    @Value("${prolog.wms.enableAutoGenBill:true}")
    private boolean enableAutoGenBill;

    @Value("${prolog.wms.enableErrorGenBatchInfo:true}")
    private boolean enableErrorGenBatchInfo;

    @Value("${prolog.wms.enableVaildateAreaCategory:true}")
    private boolean enableVaildateAreaCategory;

    @Value("${prolog.wms.enableVaildateBatchInfo2Web:false}")
    private boolean enableVaildateBatchInfo2Web;

    @Resource
    private SearchApi searchApi;

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

    @Resource
    private RcvLinesProfilesMapper rcvLinesProfilesMapper;

    @Resource
    private ControlRemoteCaller controlRemoteCaller;

    @Resource
    private BaseItemRemoteCaller baseItemRemoteCaller;

    @Resource
    private BaseItemRemoteCaller itemClient;

    @Resource
    private SupervisionCodeMapper supervisionCodeMapper;

    @Override
    public Object itemExceptionResult(List<RcvLinesDTO> rcvLinesDTOList) {
        // 接收异常处理的结果
        // 主要数据来源与oms
        // TODO
        return null;
    }

    @Override
    public Object itemException(List<RcvLinesDTO> rcvLinesDTOList) {
        // 异常处理 TODO
        /**
         * 收货员收货时若发现有异常，例如商品破损、随货同行单样式不对， 可以在WMS的界面录入异常信息，回传至OMS，采购员在OMS中审核确认
         * ，结果下传至WMS，收货员根据结果进行收货或者拒收
         */
        // 这里只录入异常信息 目前缺表,需要询问

        return null;
    }

    @Override
    public RcvLinesDTO findByPkId(String pkId) {
        AssertUtils.isNotBlank(pkId, "查询的主键id为空!");
        // 原生sql实现
        return this.mapper.findByPkId(pkId);
    }

    @Override
    public Page<RcvLinesDTO> findList(RcvLinesQueryVO queryVO, PageParam pageParam) {
        // 此处还可继续优化
        queryVO.setEnterpriseId(userUtils.getEnterpriseId());
        this.startPage(pageParam);
        List<RcvLinesDTO> list = this.mapper.findList(queryVO);
        Page<RcvLinesDTO> page2 = PageUtils.getPage(list);
        return page2;
    }

    // 此处若是多实例情况下需要分布式锁控制 也可插入时进行sql判断 TODO
    private synchronized void excuteSaveLine2(RcvLines lines, String enterpriseId, int i) {
        logger.info(lines.getItemId() + "补救保存方案执行中----------------------------------");
        // 加锁 (性能慢就替换synchronized)
        BigDecimal pieceQty = lines.getPieceQty();
        String asnLineId = lines.getAsnLineId();
        lines.setLineNum(i);
        BigDecimal findRemainQty = this.mapper.findRemainQty(asnLineId, enterpriseId);
        if (findRemainQty == null) {
            throw new BizException(String.format("收货原订单明细id[%s]对应的收货明细总量查询为空!请检查!", asnLineId));
        }
        if (findRemainQty != null && pieceQty.compareTo(findRemainQty) == 1) {
            throw new BizException(String.format("错误!第%d行数据录入有问题,实际收货数量超出单据总数量(asn)!", i));
        }
        lines.setDataVersion(0);
        lines.setEnterpriseId(enterpriseId);
        this.mapper.save(lines);
    }

    private void excuteSaveLine(RcvLines lines, String enterpriseId, int i) {
        lines.setDataVersion(0);
        lines.setEnterpriseId(enterpriseId);
        lines.setLineNum(i);
        lines.setRcvLineId(String.valueOf(SnowFlakeUtils.getId()));
        Long count = -1l;

        // 数据准确性计算
        BigDecimal pieceQty = lines.getPieceQty();
        if (pieceQty == null) {
            pieceQty = BigDecimal.ZERO;
            lines.setPieceQty(pieceQty);
        }
        BigDecimal conversionRate = lines.getConversionRate();
        if (conversionRate == null) {
            conversionRate = BigDecimal.ONE;
            lines.setPieceQty(conversionRate);
        }
        BigDecimal qty = pieceQty.divide(conversionRate, 4, RoundingMode.DOWN);
        lines.setQty(qty);

        // 校验库别是否正确,比如散件入了整件库,整件入了散件库
        if (enableVaildateAreaCategory) {
            vaildateAreaCategory(lines, i);
        }

        try {
            count = this.mapper.saveWithVaildate(lines);
        } catch (Exception e) {
            logger.info(lines.getItemId() + "原收货明细保存失败-原因->{}", e.getMessage());
            // 抛错就调用补救方案
            excuteSaveLine2(lines, enterpriseId, i);
        }
        if (count == 0) {
            throw new BizException(String.format("错误!第%d行数据录入有问题,实际收货数量超出单据总数量(asn),请检查重试!", i));
        }
    }

    private void vaildateAreaCategory(RcvLines line, int row) {
        String whAreaCategory = line.getWhAreaCategoryCode();
        if (!StringUtils.isBlank(whAreaCategory)) {
            String caseOrPiece = this.getCaseOrPiece(line);
            if ("0".equals(caseOrPiece) && BizConstant.LHK.equals(whAreaCategory)) {
                throw new BizException(String.format("第[%d]行,整件选择了零货库,请检查!", row));
            }
            if ("1".equals(caseOrPiece) && BizConstant.ZJK.equals(whAreaCategory)) {
                throw new BizException(String.format("第[%d]行,零散选择了整件库,请检查!", row));
            }
        }

    }

    private String getCaseOrPiece(RcvLines target) {
        // 是否整散
        BigDecimal pieceQty = target.getPieceQty();
        BigDecimal conversionRate = target.getConversionRate();
        BigDecimal oddCaseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN);
        BigDecimal oddPieceQty = pieceQty.subtract(oddCaseQty.multiply(conversionRate));
        // 判断数据的整散
        if (null != oddPieceQty && oddPieceQty.compareTo(BigDecimal.ZERO) == 0) {
            // 为整数
            return "0";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 0 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 零散散
            return "1";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 1 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 整散
            return "2";
        }
        return "0";
    }

    private String getCaseOrPiece(RcvLinesDTO target) {
        // 是否整散
        BigDecimal pieceQty = target.getPieceQty();
        BigDecimal conversionRate = target.getConversionRate();
        BigDecimal oddCaseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN);
        BigDecimal oddPieceQty = pieceQty.subtract(oddCaseQty.multiply(conversionRate));
        // 判断数据的整散
        if (null != oddPieceQty && oddPieceQty.compareTo(BigDecimal.ZERO) == 0) {
            // 为整数
            return "0";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 0 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 零散散
            return "1";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 1 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 整散
            return "2";
        }
        return "0";
    }

    private void excuteSaveOthers(RcvLinesDTO rcvLinesDTO, RcvLines lines, UserDTO userDTO, int row) {
        // 保存收货行其他属性
        String rcvLineId = lines.getRcvLineId();
        AssertUtils.isNotBlank(rcvLineId, "保存的收货行主键id为空(rcvLineId)!");
        String rcvHeaderId = lines.getRcvHeaderId();
        RcvLinesProfilesDTO rcvLinesProfilesDTO = rcvLinesDTO.getRcvLinesProfilesDTO();

        if (ObjectUtils.isNotNull(rcvLinesProfilesDTO)) {
            rcvLinesProfilesDTO.setRcvHeaderId(rcvHeaderId);
            rcvLinesProfilesDTO.setRcvLineId(rcvLineId);
            rcvLinesProfilesService.add(rcvLinesProfilesDTO, userDTO, row);
        }
    }

    private void buildDefaultField(RcvLinesDTO rcvLinesDTO, boolean editFlag, UserDTO userDTO) {
        // 构建基础默认字段
//		String batchId = rcvLinesDTO.getBatchId();
//		if (!editFlag && ObjectUtils.isNull(batchId)) {
//			rcvLinesDTO.setBatchId(String.valueOf(SnowFlakeUtils.getId()));
//			rcvLinesDTO.setBatchNum(String.valueOf(SnowFlakeUtils.getId()));
//		}
        Integer dataVersion = rcvLinesDTO.getDataVersion();
        if (!editFlag && dataVersion == null) {
            dataVersion = 0;
        } else {
            dataVersion = dataVersion == null ? 0 : dataVersion + 1;
        }
        rcvLinesDTO.setDataVersion(dataVersion);
        String executorUser = rcvLinesDTO.getExecutorUser();
        String rcvStockStatus = rcvLinesDTO.getStockStatus();
        if (ObjectUtils.isNull(executorUser))
            rcvLinesDTO.setExecutorUser(userDTO.getUsername());
        if (ObjectUtils.isNull(rcvStockStatus))
            rcvLinesDTO.setStockStatus("0"); // 默认结论为收货成功

        String goodsCaseCode = rcvLinesDTO.getGoodsCaseCode();
        String containerCode = rcvLinesDTO.getContainerCode();
        if (ObjectUtils.isNull(goodsCaseCode))
            rcvLinesDTO.setGoodsCaseCode("N/A");
        if (ObjectUtils.isNull(containerCode))
            rcvLinesDTO.setContainerCode("N/A");
        String isCaseOrPiece = rcvLinesDTO.getIsCaseOrPiece();
        rcvLinesDTO.setItemIsPieceOrCase(isCaseOrPiece);

    }

    private Restriction buildCondition(RcvLinesDTO rcvLinesDTO) {
        // 构建查询条件
        if (ObjectUtils.isNull(rcvLinesDTO))
            return null;

        String rcvHeaderId = rcvLinesDTO.getRcvHeaderId();
        String asnHeaderId = rcvLinesDTO.getAsnHeaderId();
        String itemId = rcvLinesDTO.getItemId();
        String batchNum = rcvLinesDTO.getBatchNum();
        String stockStatus = rcvLinesDTO.getStockStatus();

        Restriction r0 = Restrictions.eq("enterpriseId", userUtils.getEnterpriseId());
        Restriction r1 = StringUtils.isBlank(rcvHeaderId) ? null : Restrictions.eq("rcvHeaderId", rcvHeaderId);
        Restriction r2 = StringUtils.isBlank(asnHeaderId) ? null : Restrictions.eq("asnHeaderId", asnHeaderId);
        Restriction r3 = StringUtils.isBlank(itemId) ? null : Restrictions.eq("itemId", itemId);
        Restriction r4 = StringUtils.isBlank(batchNum) ? null : Restrictions.like("batchNum", "%" + batchNum + "%"); // 批号模糊
        Restriction r5 = StringUtils.isBlank(stockStatus) ? null : Restrictions.eq("rcvStockStatus", stockStatus);

        return Restrictions.and(r0, r1, r2, r3, r4, r5);
    }

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

    @Override
    public List<RcvLinesDTO> searchByIdList(List<String> rcvLineIdList) {
        if (ObjectUtils.isNull(rcvLineIdList))
            return null;

        String[] array = rcvLineIdList.toArray(new String[rcvLineIdList.size()]);
        List<RcvLines> list = this.mapper.findByIds(RcvLines.class, array, null);
        List<RcvLinesDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
            RcvLinesDTO target = new RcvLinesDTO();
            BeanUtils.copyProperties(p, target);
            return target;
        }).collect(Collectors.toList());
        return collect;

    }

    @Override
    @Transactional
    public Object batchAdd(List<RcvLinesDTO> rcvLinesDTOList) {
        UserDTO userDTO = userUtils.getUserDTO();
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            RcvLines rcvLines = new RcvLines();
            BeanUtils.copyProperties(rcvLinesDTO, rcvLines);
            this.vaildateModel(rcvLines, false, userDTO);
            this.setBaseSysField(rcvLines, false, userDTO);
            this.vaildateModelRepeated(rcvLines, false, userDTO);
            this.mapper.save(rcvLines);
        }
        return "";
    }

    @Override
    @Transactional
    public Object batchEdit(List<RcvLinesDTO> rcvLinesDTOList) {
        UserDTO userDTO = userUtils.getUserDTO();
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            RcvLines rcvLines = new RcvLines();
            BeanUtils.copyProperties(rcvLinesDTO, rcvLines);
            this.vaildateModel(rcvLines, true, userDTO);
            this.setBaseSysField(rcvLines, true, userDTO);
            this.vaildateModelRepeated(rcvLines, true, userDTO);
            this.mapper.updateWithValidate(rcvLines,
                    p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
        }
        return true;
    }

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

    private void vaildateModel(RcvLines rcvLines, Boolean editFlag, UserDTO userDTO) {
        if (!editFlag) {
        } else {
        }
    }

    private void vaildateModelRepeated(RcvLines rcvLines, Boolean editFlag, UserDTO userDTO) {
        if (!editFlag) {
        } else {
        }
    }

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

    @Override
    public Object add(RcvLinesDTO rcvLinesDTO) {
        UserDTO userDTO = userUtils.getUserDTO();
        RcvLines rcvLines = new RcvLines();
        BeanUtils.copyProperties(rcvLinesDTO, rcvLines);
        this.vaildateModel(rcvLines, false, userDTO);
        this.setBaseSysField(rcvLines, userDTO);
        this.vaildateModelRepeated(rcvLines, false, userDTO);
        this.mapper.save(rcvLines);
        return "";
    }

    @Override
    public Object edit(String pkId, RcvLinesDTO rcvLinesDTO) {
        UserDTO userDTO = userUtils.getUserDTO();
        RcvLines rcvLines = new RcvLines();
        BeanUtils.copyProperties(rcvLinesDTO, rcvLines);
        this.vaildateModel(rcvLines, true, userDTO);
        this.setBaseSysField(rcvLines, true, userDTO);
        this.vaildateModelRepeated(rcvLines, true, userDTO);
        this.mapper.updateWithValidate(rcvLines, p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
        return "";
    }

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

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

    @Override
    public Object batchAdd(List<RcvLinesDTO> rcvLinesDTOList, String masterId, UserDTO userDTO, String mtlOwnerId,
                           String warehouseId, Map<String, Object> flowparam) {
        return null;
    }

    @Resource
    private StrategyClient strategyClient;

    @Override
    public Object testStrategy(List<RcvLinesDTO> rcvLinesDTOList) {
        RcvLinesDTO rcvLinesDTO = rcvLinesDTOList.get(0);
        String mtlOwnerId = rcvLinesDTO.getMtlOwnerId();
        String warehouseId = rcvLinesDTO.getWarehouseId();
        String enterpriseId = userUtils.getEnterpriseId();
        // 测试寻库别
        RestMessage<StrategyDTO> strategyResult = strategyClient.getStrategyDTO(enterpriseId, "InStock", mtlOwnerId,
                warehouseId);
        if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null)
            throw new BizException("未找到有效的策略");
        StrategyDTO strategyDTO = strategyResult.getData();
        Strategy strategy = null;
        try {
            strategy = strategyDTO.createStrategy();
        } catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
            // 打印日志
        }
        if (ObjectUtils.isNotNull(strategy)) {
            for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOList) {
                WhAreaCategoryContext context = new WhAreaCategoryContext();
                WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();
                rcvLineData.setBillType("1");
                rcvLineData.setIsCase("0");
                rcvLineData.setQty(8d);
                rcvLineData.setIsPieceOrCase(false);
                rcvLineData.setStorageStatus("1");
                context.setRcvLineData(rcvLineData);
                try {
                    strategy.execute(context); // 捕捉异常
                } catch (StrategyExecuteException e) {
                    logger.error("策略执行失败,原因->", e);
                    e.printStackTrace();
                }
                boolean completed = context.completed();
                if (completed) {
                    // 找到匹配的策略
                    List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
                    String join = String.join(",", targetAreaCategoryCodes);
                    rcvLinesDTO2.setWarehouseAreaCodes(join);
                    Integer lineNum = rcvLinesDTO2.getLineNum();
                    logger.info(String.format("第[%d]行,推荐库别[%s]", lineNum, join));
                }

//				Boolean flag = true;
//				while (flag) {
//					boolean completed = context.completed();
//					if (completed) {
//						flag = false;
//						List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
//						System.out.println(targetAreaCategoryCodes);
//					}
//				}
            }

        }
        return null;
    }

    private boolean filter(Object p) {
        Map map = (Map) p;
        String object = (String) map.get("warehouseAreaCategoryCode");
        if (StringUtils.isBlank(object)) {
            return false;
        }
        return true;
    }

    private String fetch(Object p) {
        Map map = (Map) p;
        return (String) map.get("warehouseAreaCategoryCode");
    }

    @Override
    @Transactional
    public Object batchAdd(List<RcvLinesDTO> rcvLinesDTOList, String masterId, UserDTO userDTO, String mtlOwnerId,
                           String warehouseId, CargoChangeIn cargoChangeIn) {
        if (null == userDTO)
            userDTO = userUtils.getUserDTO();
        int i = 0;
        boolean editFlag = Boolean.FALSE;
        Date now = new Date();
        String enterpriseId = userDTO.getEnterpriseId();
        // 这里先使用模拟的默认字段z
//		Integer doubleCheckFlag = new Random().nextInt(2); // 随机0和1 单人0双人1
        Set<String> rcvLineIdSet = new HashSet<>();
        boolean b = rcvLinesDTOList.stream().anyMatch(x -> x.getIsRetrospect() == 1);
        Boolean isLock = false;
        if(b){
            Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
            Restriction r1 = Restrictions.eq("refBillId", rcvLinesDTOList.get(0).getAsnHeaderId());
            Restriction r2 = Restrictions.eq("unlock", 1);
            Restriction r3 = Restrictions.and(r1,r2);
            criteria1.setRestriction(r3);
            long countByCriteria = mapper.findCountByCriteria(criteria1);
            if(countByCriteria>0){
                isLock = true;
            }
        }
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            i++;
            rcvLineIdSet.add(rcvLinesDTO.getRcvLineId());
            excuteVailddateExtRcvType(rcvLinesDTO, i);
            // 校验散件必须绑容器
            vaildateContainerCode(rcvLinesDTO, i);
            // 头表id
            rcvLinesDTO.setRcvHeaderId(masterId);
            // 构建默认字段
            this.buildDefaultField(rcvLinesDTO, editFlag, userDTO);
            // 校验基础数据
            this.vaildateModel(rcvLinesDTO, editFlag, userDTO, i, validator, "保存的收货行操作");

//			vaildateLotInfo(rcvLinesDTO, i);

            RcvLines lines = new RcvLines();
            BeanUtils.copyProperties(rcvLinesDTO, lines);
            // 设置系统级字段
            super.setBaseSysField(lines, editFlag, userDTO, now);
            // 校验数据库重复
            this.vaildateModelRepeated(lines, editFlag, userDTO);
            lines.setMtlOwnerId(mtlOwnerId);
            lines.setWarehouseId(warehouseId);
            Integer itemHealthIsDouble = lines.getItemHealthIsDouble();
            if (itemHealthIsDouble == null) {
                lines.setItemHealthIsDouble(0); // 默认单人质检
            }

            if(!StringUtils.isEmpty(rcvLinesDTO.getItemHealthType())){
                lines.setAttribute1(rcvLinesDTO.getItemHealthType());
            }

            if(!StringUtils.isEmpty(rcvLinesDTO.getLocNo())){
                lines.setAttribute2(rcvLinesDTO.getLocNo());
            }

            String batchNum = lines.getBatchNum();
            String batchId = lines.getBatchId();
            if (StringUtils.isBlank(batchId)) {
                lines.setBatchId(batchNum);
            }
            // 批号判断 为*或空增加当前时间100年(已经处理)

            // 校验效期 90天内
//			Date batchProductionDate = lines.getBatchProductionDate();
//			if (batchProductionDate.before(now)
//					&& expiredDays < DateUtils.subtract(batchProductionDate, now, ChronoUnit.DAYS)) {
//				// TODO 回传到OMS 审核状态 如要收货 需先录入异常信息回传到OMS审核后再收货
//				// 给予提示
//				throw new BizException(String.format("警告!第%d行数据录入有问题,商品近效期小于%d天.", i, expiredDays));
//
//			}

            // 拆分+并发 控不住 // 只能在全部保存后校验

            // 保存收货行数据,校验数量是否超出(并发考虑)
            excuteSaveLine(lines, enterpriseId, i);

            String rcvLineId = lines.getRcvLineId();
            String itemId = lines.getItemId();
            rcvLinesDTO.setRcvLineId(rcvLineId);
            excuteSaveOthers(rcvLinesDTO, lines, userDTO, i);
            try {
                excuteSavePic(rcvLinesDTO, lines, userDTO, i);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //校验监管码更新监管码为收货单纬度
            if(rcvLinesDTO.getIsRetrospect()==1&&!rcvLinesDTO.getStockStatus().equals("3")){
                Criteria criteria = Criteria.forClass(SupervisionCode.class);
                criteria.restrictionBuilder().eq("refBillId",rcvLinesDTO.getAsnHeaderId())
                        .eq("refBillLineId",rcvLinesDTO.getRefAsnLineId())
                        .eq("creator",userDTO.getId());
                criteria.buildRestriction();
                List<SupervisionCode> supervisionCodeList = supervisionCodeMapper.findByCriteria(criteria);
                if(isLock){
                    if(CollectionUtil.isNotEmpty(supervisionCodeList)){
                        String[] ids = supervisionCodeList.stream().map(x -> x.getId()).toArray(String[]::new);
                        criteria = Criteria.forClass(SupervisionCode.class);
                        criteria.restrictionBuilder().in("id",ids);
                        criteria.buildRestriction();
                        supervisionCodeMapper.updateMapByCriteria(MapUtils.put("refBillId",lines.getRcvHeaderId()).put("refBillLineId",lines.getRcvLineId())
                                .put("manufacturerLotNum",rcvLinesDTO.getManufacturerLotNum())
                                        .put("productionDate",rcvLinesDTO.getBatchProductionDate()).put("expiredDate",rcvLinesDTO.getBatchExpiredDate()).getMap(),criteria);
                    }
                }else{
                    if(CollectionUtil.isEmpty(supervisionCodeList)){
                        throw new BizException(String.format("第%d行请扫描监管码",i));
                    }
                    BigDecimal reduce = supervisionCodeList.stream().map(x -> new BigDecimal(x.getPackSize())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    if(reduce.compareTo(rcvLinesDTO.getPieceQty())!=0){
                        throw new BizException(String.format("第%d行收货数量与监管码数量不一致",i));
                    }
                    String[] ids = supervisionCodeList.stream().map(x -> x.getId()).toArray(String[]::new);
                    criteria = Criteria.forClass(SupervisionCode.class);
                    criteria.restrictionBuilder().in("id",ids);
                    criteria.buildRestriction();
                    supervisionCodeMapper.updateMapByCriteria(MapUtils.put("refBillId",lines.getRcvHeaderId()).put("refBillLineId",lines.getRcvLineId())
                            .put("manufacturerLotNum",rcvLinesDTO.getManufacturerLotNum())
                                    .put("productionDate",rcvLinesDTO.getBatchProductionDate()).put("expiredDate",rcvLinesDTO.getBatchExpiredDate()).getMap(),criteria);
                }
            }
        }

        return true;
    }

    private void excuteSavePic(RcvLinesDTO rcvLinesDTO, RcvLines lines, UserDTO userDTO, int i) {
        List<RcvLinesPicDTO> rcvLinesPicDTOList = rcvLinesDTO.getRcvLinesPicDTOList();
        if (rcvLinesPicDTOList != null) {
            Date now = new Date();
            List<BaseBizFile> bizFileList = new ArrayList<BaseBizFile>();
            for (int j = 0; j < rcvLinesPicDTOList.size(); j++) {
                RcvLinesPic rcvLinesPic = new RcvLinesPic();
                BeanUtils.copyProperties(rcvLinesPicDTOList.get(j), rcvLinesPic);
                rcvLinesPic.setRcvLineId(lines.getRcvLineId());
                rcvLinesPic.setRcvHeaderId(lines.getRcvHeaderId());
                rcvLinesPic.setItemId(lines.getItemId());
                rcvLinesPic.setCreator(userDTO.getId());
                rcvLinesPic.setCreatorName(userDTO.getUsername());
                rcvLinesPic.setGmtCreate(now);
                rcvLinesPic.setEntId(userDTO.getEnterpriseId());
                rcvLinesPic.setModifier(userDTO.getId());
                rcvLinesPic.setModifierName(userDTO.getUsername());
                rcvLinesPic.setGmtModified(now);
                rcvLinesPicMapper.save(rcvLinesPic);

                BaseBizFile bf = new BaseBizFile();
                bf.setBizId(rcvLinesDTO.getItemId()+"-"+rcvLinesDTO.getManufacturerLotNum());
                bf.setBizType("04");
                bf.setCode(rcvLinesDTO.getItemId());
                bf.setDataType("");
                String picFilename = rcvLinesPic.getPicFilename();
                if (StringUtils.isBlank(picFilename)) {
                    picFilename = rcvLinesPic.getPicFileurl();
                    rcvLinesPic.setPicFilename(picFilename);
                }
                bf.setFileName(picFilename);
//				bf.setFileName(rcvLinesPic.getPicFilename());
                bf.setFileUrl(rcvLinesPic.getPicFileurl());
                bf.setFileFolderId(rcvLinesPic.getPicFileurl());
                bf.setName(rcvLinesDTO.getManufacturerLotNum());
                bizFileList.add(bf);
            }

            // 保存到图片管理服务中去
            if (ObjectUtils.isNotNull(bizFileList)) {
                try {
                    Log.info("同步给图片管理数据=>" + JsonUtils.toString(bizFileList));
                    RestMessage<Object> add = commonCaller.add(bizFileList);
                    if (add == null || !add.isSuccess()) {
                        String msg = "";
                        if (add != null) {
                            msg = add.getMessage();
                        }
                        logger.error("远程调用图片管理新增异常,错误原因=>" + msg);
                    }
                } catch (Exception e) {
                    logger.error("远程调用图片管理新增接口异常,错误原因=>" + e.getMessage());
                    e.printStackTrace();
                }
            }
        }

    }

    private void vaildateLotInfo(RcvLinesDTO rcvLinesDTO, int i) {
        String stockStatus = rcvLinesDTO.getStockStatus();
        if (!BizConstant.REJECT.equals(stockStatus)) {
            String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
            String showProductionDate = rcvLinesDTO.getShowProductionDate();
            String showExpiredDate = rcvLinesDTO.getShowExpiredDate();
            if (StringUtils.isBlank(manufacturerLotNum) || StringUtils.isBlank(showProductionDate)
                    || StringUtils.isBlank(showExpiredDate)) {
                throw new BizException(String.format("第[%d]行,请检查批号,生产日期,有效期至是否为空!", i));
            }
        }

    }

    private void excuteVailddateExtRcvType(RcvLinesDTO rcvLinesDTO, int row) {
        String rcvType = rcvLinesDTO.getRcvType();
        if (!BizConstant.REJECT.equals(rcvLinesDTO.getStockStatus())) {
            if (rcvType.equals(BizConstant.BLANK_ENTITY_IN) || rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN)) {
                // 其他入,必须有其他出的货位
                String whLocatorId = rcvLinesDTO.getWhLocatorId();
                String whAreaCode = rcvLinesDTO.getWhAreaCode();
                String whAreaCategoryCode = rcvLinesDTO.getWhAreaCategoryCode();
                if (StringUtils.isBlank(whLocatorId)) {
                    throw new ParameterException(String.format("第[%d]行,其他入库需绑定货位(whLocatorId),不能为空!", row));
                }
                if (StringUtils.isBlank(whAreaCode)) {
                    throw new ParameterException(String.format("第[%d]行,其他入库需绑定库区(whAreaCode),不能为空!", row));
                }
                if (StringUtils.isBlank(whAreaCategoryCode)) {
                    throw new ParameterException(String.format("第[%d]行,其他入库需绑定库别(whAreaCategoryCode),不能为空!", row));
                }
            }
        }
    }

    private void vaildateContainerCode(RcvLinesDTO rcvLinesDTO, int i) {
        String rcvType = rcvLinesDTO.getRcvType();
        BigDecimal pieceQty = rcvLinesDTO.getPieceQty();
        if (pieceQty == null)
            pieceQty = BigDecimal.ZERO;
        BigDecimal conversionRate = rcvLinesDTO.getConversionRate();
        if (conversionRate == null || conversionRate.compareTo(BigDecimal.ZERO) == 0)
            conversionRate = BigDecimal.ONE;
        // 计算出整件,零散
        BigDecimal caseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN); // 整件
        BigDecimal multiply = caseQty.multiply(conversionRate);
        BigDecimal oddPieceQty = pieceQty.subtract(multiply); // 零散
        String itemIsPieceOrCase = rcvLinesDTO.getItemIsPieceOrCase();
        String containerCode = rcvLinesDTO.getContainerCode();
        String format = String.format("第[%d]行,", i);
        if (StringUtils.isBlank(itemIsPieceOrCase))
            itemIsPieceOrCase = "0"; // 默认整散合一
        if (rcvType.equals(BizConstant.PURCHASE_IN) || rcvType.equals(BizConstant.SALE_RETURN_IN)) {
            if (itemIsPieceOrCase.equals("1") && BigDecimal.ZERO.compareTo(caseQty) == -1
                    && BigDecimal.ZERO.compareTo(oddPieceQty) == -1)
                throw new BizException(format + "不是整散合一属性,需要拆分整件,散件!"); // 整散需分开 且 (有整件也有散件)
            if (itemIsPieceOrCase.equals("1") && StringUtils.isBlank(containerCode)
                    && BigDecimal.ZERO.compareTo(caseQty) == 0 && BigDecimal.ZERO.compareTo(oddPieceQty) == -1)
                throw new BizException(format + "不是整散合一属性,且只有散件,但散件没有绑定容器!"); // 整散需分开 且 只有散件,但散件没有绑定容器
        }
    }

    @Transactional
    @TxTransaction(isStart = true)
    @Override
    public Object batchAdd(List<RcvLinesDTO> rcvLinesDTOList, RcvHeadersDTO rcvHeadersDTO, UserDTO userDTO,
                           CargoChangeIn cargoChangeIn,boolean ztFlag) {
        AssertUtils.isNotEmpty(rcvLinesDTOList, "操作的集合数据为空!");
        String masterId = rcvHeadersDTO.getRcvHeaderId();
        String mtlOwnerId = rcvHeadersDTO.getMtlOwnerId();
        String warehouseId = rcvHeadersDTO.getWarehouseId();
        AssertUtils.isNotBlank(masterId, "头表id为空,请重试!");
        AssertUtils.isNotBlank(mtlOwnerId, "货主id为空,请重试!");
        AssertUtils.isNotBlank(warehouseId, "仓库id为空,请重试!");

        Date now = new Date();
        // Step0: 处理批号及效期 以及冷藏商品校验
        String rcvType = rcvHeadersDTO.getRcvType();

        // 批次初始化
//		excuteHandlerLotNum(rcvType, rcvLinesDTOList, now, userDTO); // 被上级代替

        Object obj = null;
        // Step1: 不同收货类型的数据处理
        switch (rcvType) {
            case BizConstant.PURCHASE_IN:
                // 普通采购入库处理
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.SALE_RETURN_IN:
                // 销售退回入库处理
                obj = this.saleReturnBatchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.ALLOT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.MOVE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.ACCOUNT_REG_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.OVERSTEP_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.STRAIGHT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.HOSTED_IN:
                // 代管入库
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.WAIT_CHECK_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.INSTRUMENT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.FREE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_ENTITY_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_RETURN_ENTITY_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_RETURN_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.FACTORY_MAINTENANCE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.CUSTORM_MAINTENANCE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            default:
                break;
        }

        // Step2: 调用库存服务获取批次id,批次号(此处生成批次看是否可以在保存收货行前)
//		Object info = excuteHandlerBatchInfo(rcvHeadersDTO, rcvType, rcvLinesDTOList, now); 被上级代替

        // 可以拿到后手校验 RcvTypeService
        int row = 0;
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            row++;
            if (!BizConstant.REJECT.equals(rcvLinesDTO.getStockStatus())) {
                String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
                if (StringUtils.isBlank(manufacturerLotNum))
                    throw new BizException(String.format("第[%d]行,批次id(manufacturerLotNum)相关数据为空!请联系相关人员处理或刷新重试!", row));
            }
        }

        // Step4: 推送任务,根据结论退不同的任务池,可考虑是否异步
        Map<String, List<RcvLinesDTO>> collect = Optional.ofNullable(rcvLinesDTOList).orElse(Collections.emptyList())
                .stream().distinct().collect(Collectors.groupingBy(RcvLinesDTO::getStockStatus));
        AssertUtils.notNull(collect, "收货行数据根据收货结论分组为空!");
        RcvTypeStrategyEnum rcvTypeStrategyEnum = taskHelper.getRcvTypeStrategyEnum(masterId);// 获取策略
        RqcStrategyEnum rqcStrategyEnum = null;
        /* 添加收货获取质检 --- on 2022-07-25 by 陈浩 ---开始 */
       /* if (rcvType.equals(BizConstant.PURCHASE_IN) || rcvType.equals(BizConstant.ALLOT_IN)
                || rcvType.equals(BizConstant.SALE_RETURN_IN) || rcvType.equals(BizConstant.FACTORY_MAINTENANCE_IN)
                || rcvType.equals(BizConstant.CUSTORM_MAINTENANCE_IN)) {
            rqcStrategyEnum = taskHelper.getRqcRcvStrategyEnum(masterId);
            rqcStrategyEnum = new RqcStrategyEnum();
        } else {
            rqcStrategyEnum = taskHelper.getRqcStrategyEnum(masterId);
        }*/

       //获取物料大类字典
        RestMessage<List<BaseCommonDict>> commonRest = commonCaller.getDictBasicListByCodes("item_health_category", null);
       if(!commonRest.isSuccess()&&CollectionUtil.isEmpty(commonRest.getData())){
           throw new BizException("商品大类字典查询失败");
       }
        List<BaseCommonDict> data = commonRest.getData();
        BaseCommonDict commonDict = data.stream().filter(x -> x.getDictName().indexOf("物料")>-1).findFirst().orElse(null);
        if(commonDict==null){
            throw new BizException("物料大类字典查询失败");
        }

        /* 添加收货获取质检 --- on 2022-07-25 by 陈浩 ---jieshu */
        for (List<RcvLinesDTO> rcvLinesDTO : collect.values()) {
            String rcvStockStatus = rcvLinesDTO.get(0).getStockStatus();
            // 调用策略工厂来组织执行器执行任务
            RcvSubjectFactory factory = new RcvSubjectFactoryS1Impl();
            //物料大类不走质检
            List<RcvLinesDTO> collect1 = rcvLinesDTO.stream().filter(x -> x.getCategoryId().equals(commonDict.getDictCode())).collect(Collectors.toList());
            List<RcvLinesDTO> collect2 = rcvLinesDTO.stream().filter(x -> !x.getCategoryId().equals(commonDict.getDictCode())).collect(Collectors.toList());
            if(ztFlag){
                //直通的默认走质检
                rqcStrategyEnum = RqcStrategyEnum.rqcStrategy4;
                Map<String, Object> map = new HashedMap<>();
                map.put("data", rcvLinesDTO);
                map.put("mtlOwnerId", mtlOwnerId);
                map.put("warehouseId", warehouseId);
                ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);// 获取对应结论
                obj = factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, false);// 调用任务生成
            }else {
                if(collect1.size()>0){
                    rqcStrategyEnum = RqcStrategyEnum.rqcStrategy1;
                    Map<String, Object> map = new HashedMap<>();
                    map.put("data", collect1);
                    map.put("mtlOwnerId", mtlOwnerId);
                    map.put("warehouseId", warehouseId);
                    ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);// 获取对应结论
                    obj = factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, false);// 调用任务生成
                }
                if(collect2.size()>0){
                    rqcStrategyEnum = RqcStrategyEnum.rqcStrategy4;
                    Map<String, Object> map = new HashedMap<>();
                    map.put("data", collect2);
                    map.put("mtlOwnerId", mtlOwnerId);
                    map.put("warehouseId", warehouseId);
                    ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);// 获取对应结论
                    obj = factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, false);// 调用任务生成
                }
            }

//            Map<String, Object> map = new HashedMap<>();
//            map.put("data", rcvLinesDTO);
//            map.put("mtlOwnerId", mtlOwnerId);
//            map.put("warehouseId", warehouseId);
//            ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);// 获取对应结论
//            //厂家维修入库，客户维修入库 不走质检  --需求方说只有这两种单据不走质检
////            if (rcvType.equals(BizConstant.FACTORY_MAINTENANCE_IN) || rcvType.equals(BizConstant.CUSTORM_MAINTENANCE_IN)) {
////                rqcStrategyEnum = RqcStrategyEnum.rqcStrategy1;
////            } else {
////                rqcStrategyEnum = RqcStrategyEnum.rqcStrategy4;
////            }
//                obj = factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, false);// 调用任务生成
        }

        // TODO 保存成功后 需要回传erp 效期
        // Step5: 回传erp

        // Step6: 容器占用(拒收不占用容器)
        List<String> containerCodeList = rcvLinesDTOList.stream()
                .filter(p -> !StringUtils.isBlank(p.getContainerCode()) && !p.getStockStatus().equals("3"))
                .map(RcvLinesDTO::getContainerCode).collect(Collectors.toList());
        ContainerQueryVO cVO = new ContainerQueryVO();
        cVO.setWarehouseId(warehouseId);
        cVO.setEnterpriseId(userDTO.getEnterpriseId());
        cVO.setContainerCodeList(containerCodeList);
        try {
            if (!ObjectUtils.isNull(containerCodeList)) {
                // 容器占用
                baseWmsWarehouseCaller.used(cVO);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 看是否用异步线程去跑 TODO
        // 跑自动单据,空进无实物,空退无实物,调账:空进有实物,空退有实物
        boolean allMatch = rcvLinesDTOList.stream().allMatch(p -> p.getStockStatus().equals(BizConstant.REJECT));
        if (!allMatch && enableAutoGenBill) {
            if (rcvType.equals(BizConstant.BLANK_IN) || rcvType.equals(BizConstant.BLANK_RETURN_IN)
                    || rcvType.equals(BizConstant.BLANK_ENTITY_IN)
                    || rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN)) {
                autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO, true, cargoChangeIn);
            }
            if (rcvHeadersDTO.getAutoGen()) {
                autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO, true, cargoChangeIn);
            }

//			if (rcvType.equals(BizConstant.HOSTED_IN)) {
//				// 代管入库的处理,若是流通货主,自动验收,走货位推荐逻辑生生上架任务
//				Map<String, Object> queryMap = new HashMap<>();
//				queryMap.put("cargoOwnerId", rcvHeadersDTO.getMtlOwnerId());
//				List<Map> searchForMap = null;
//				try {
//					searchForMap = searchApi.searchForMap("getCargoOwnerProp", queryMap);
//				} catch (Exception e) {
//					logger.info("获取货主属性失败,原因{}", e);
//				}
//				if (!ObjectUtils.isNull(searchForMap)) {
//					Map map = searchForMap.get(0);
//					String cargoOwnerProp = (String) map.get("cargoOwnerProp");
//					Integer isHostedRcv = (Integer) map.get("isHostedRcv");
//					if (isHostedRcv != null && 0 == isHostedRcv) {
//						// 此货主不支持代管业务
//						throw new BizException("此货主不支持代管业务!请设置!");
//					}
//					if (!StringUtils.isBlank(cargoOwnerProp) && "0".equals(cargoOwnerProp)) {
//						// 流通货主
//						autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO,false);
//					}
//					if (!StringUtils.isBlank(cargoOwnerProp) && "1".equals(cargoOwnerProp)) {
//						// 生产货主
//					}
//				}
//			}
        }
//		if (!ObjectUtils.isNull(info)) {
//			return info;
//		}
        return obj;
    }

    @Transactional
    @TxTransaction(isStart = true)
    @Override
    public Object rfBatchAdd(List<RcvLinesDTO> rcvLinesDTOList, RcvHeadersDTO rcvHeadersDTO, UserDTO userDTO,
                             CargoChangeIn cargoChangeIn) {
        AssertUtils.isNotEmpty(rcvLinesDTOList, "操作的集合数据为空!");
        String masterId = rcvHeadersDTO.getRcvHeaderId();
        String mtlOwnerId = rcvHeadersDTO.getMtlOwnerId();
        String warehouseId = rcvHeadersDTO.getWarehouseId();
        AssertUtils.isNotBlank(masterId, "头表id为空,请重试!");
        AssertUtils.isNotBlank(mtlOwnerId, "货主id为空,请重试!");
        AssertUtils.isNotBlank(warehouseId, "仓库id为空,请重试!");

        Date now = new Date();
        // Step0: 处理批号及效期 以及冷藏商品校验
        String rcvType = rcvHeadersDTO.getRcvType();

        // 批次初始化
//		excuteHandlerLotNum(rcvType, rcvLinesDTOList, now, userDTO); // 被上级代替

        Object obj = null;
        // Step1: 不同收货类型的数据处理
        switch (rcvType) {
            case BizConstant.PURCHASE_IN:
                // 普通采购入库处理
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.SALE_RETURN_IN:
                // 销售退回入库处理
                obj = this.saleReturnBatchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.ALLOT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.MOVE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.ACCOUNT_REG_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.OVERSTEP_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.STRAIGHT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.HOSTED_IN:
                // 代管入库
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.WAIT_CHECK_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.INSTRUMENT_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.FREE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_ENTITY_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_RETURN_ENTITY_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.BLANK_RETURN_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.FACTORY_MAINTENANCE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            case BizConstant.CUSTORM_MAINTENANCE_IN:
                obj = this.batchAdd(rcvLinesDTOList, masterId, userDTO, mtlOwnerId, warehouseId, cargoChangeIn);
                break;
            default:
                break;
        }

        // Step2: 调用库存服务获取批次id,批次号(此处生成批次看是否可以在保存收货行前)
//		Object info = excuteHandlerBatchInfo(rcvHeadersDTO, rcvType, rcvLinesDTOList, now); 被上级代替

        // 可以拿到后手校验 RcvTypeService
        int row = 0;
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            row++;
            if (!BizConstant.REJECT.equals(rcvLinesDTO.getStockStatus())) {
                String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
                if (StringUtils.isBlank(manufacturerLotNum))
                    throw new BizException(String.format("第[%d]行,批次id(manufacturerLotNum)相关数据为空!请联系相关人员处理或刷新重试!", row));
            }
        }

        // Step4: 推送任务,根据结论退不同的任务池,可考虑是否异步
        Map<String, List<RcvLinesDTO>> collect = Optional.ofNullable(rcvLinesDTOList).orElse(Collections.emptyList())
                .stream().distinct().collect(Collectors.groupingBy(RcvLinesDTO::getStockStatus));
        AssertUtils.notNull(collect, "收货行数据根据收货结论分组为空!");
        RcvTypeStrategyEnum rcvTypeStrategyEnum = taskHelper.getRcvTypeStrategyEnum(masterId);// 获取策略
        RqcStrategyEnum rqcStrategyEnum = null;
        rqcStrategyEnum = taskHelper.getRqcRcvStrategyEnum(masterId);
        /* 添加收货获取质检 --- on 2022-07-25 by 陈浩 ---jieshu */

        for (List<RcvLinesDTO> rcvLinesDTO : collect.values()) {
            String rcvStockStatus = rcvLinesDTO.get(0).getStockStatus();
            // 调用策略工厂来组织执行器执行任务
            RcvSubjectFactory factory = new RcvSubjectFactoryS1Impl();
            Map<String, Object> map = new HashedMap<>();
            map.put("data", rcvLinesDTO);
            map.put("mtlOwnerId", mtlOwnerId);
            map.put("warehouseId", warehouseId);
            ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);// 获取对应结论
            obj = factory.rfExcuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, false);// 调用任务生成
        }

        // TODO 保存成功后 需要回传erp 效期
        // Step5: 回传erp

        // Step6: 容器占用(拒收不占用容器)
        List<String> containerCodeList = rcvLinesDTOList.stream()
                .filter(p -> !StringUtils.isBlank(p.getContainerCode()) && !p.getStockStatus().equals("3"))
                .map(RcvLinesDTO::getContainerCode).collect(Collectors.toList());
        ContainerQueryVO cVO = new ContainerQueryVO();
        cVO.setWarehouseId(warehouseId);
        cVO.setEnterpriseId(userDTO.getEnterpriseId());
        cVO.setContainerCodeList(containerCodeList);
        try {
            if (!ObjectUtils.isNull(containerCodeList)) {
                // 容器占用
                baseWmsWarehouseCaller.used(cVO);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        // 看是否用异步线程去跑 TODO
        // 跑自动单据,空进无实物,空退无实物,调账:空进有实物,空退有实物
        boolean allMatch = rcvLinesDTOList.stream().allMatch(p -> p.getStockStatus().equals(BizConstant.REJECT));
        if (!allMatch && enableAutoGenBill) {
            if (rcvType.equals(BizConstant.BLANK_IN) || rcvType.equals(BizConstant.BLANK_RETURN_IN)
                    || rcvType.equals(BizConstant.BLANK_ENTITY_IN)
                    || rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN)) {
                autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO, true, cargoChangeIn);
            }
            if (rcvHeadersDTO.getAutoGen()) {
                autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO, true, cargoChangeIn);
            }

//			if (rcvType.equals(BizConstant.HOSTED_IN)) {
//				// 代管入库的处理,若是流通货主,自动验收,走货位推荐逻辑生生上架任务
//				Map<String, Object> queryMap = new HashMap<>();
//				queryMap.put("cargoOwnerId", rcvHeadersDTO.getMtlOwnerId());
//				List<Map> searchForMap = null;
//				try {
//					searchForMap = searchApi.searchForMap("getCargoOwnerProp", queryMap);
//				} catch (Exception e) {
//					logger.info("获取货主属性失败,原因{}", e);
//				}
//				if (!ObjectUtils.isNull(searchForMap)) {
//					Map map = searchForMap.get(0);
//					String cargoOwnerProp = (String) map.get("cargoOwnerProp");
//					Integer isHostedRcv = (Integer) map.get("isHostedRcv");
//					if (isHostedRcv != null && 0 == isHostedRcv) {
//						// 此货主不支持代管业务
//						throw new BizException("此货主不支持代管业务!请设置!");
//					}
//					if (!StringUtils.isBlank(cargoOwnerProp) && "0".equals(cargoOwnerProp)) {
//						// 流通货主
//						autoRqcHandler.autoRqc(rcvLinesDTOList, rcvHeadersDTO, userDTO,false);
//					}
//					if (!StringUtils.isBlank(cargoOwnerProp) && "1".equals(cargoOwnerProp)) {
//						// 生产货主
//					}
//				}
//			}
        }
//		if (!ObjectUtils.isNull(info)) {
//			return info;
//		}
        return obj;
    }

    private Object excuteHandlerBatchInfo(RcvHeadersDTO rcvHeadersDTO, String rcvType,
                                          List<RcvLinesDTO> rcvLinesDTOList, Date now) {
        Object obj = null;
        // 根据条件分组是否是新增还是更新
        Map<Integer, List<RcvLinesDTO>> collect = rcvLinesDTOList.stream().filter(p -> p.getEditFlag() != null)
                .collect(Collectors.groupingBy(RcvLinesDTO::getEditFlag));
        if (!ObjectUtils.isNull(collect)) {
            for (Entry<Integer, List<RcvLinesDTO>> entry : collect.entrySet()) {
                Integer key = entry.getKey();
                List<RcvLinesDTO> value = entry.getValue();
                if (key == 1) {
                    // 批号信息更新
//					value.stream().anyMatch(p -> StringUtils.isBlank(p.getBatchId()));
                    ValidList<InvStockBatchNumberUpdate> batchNumbers = new ValidList<>();
                    for (RcvLinesDTO rcvLinesDTO : value) {
                        String stockStatus = rcvLinesDTO.getStockStatus();
                        if (BizConstant.REJECT.equals(stockStatus)) {
                            String lotNum = rcvLinesDTO.getManufacturerLotNum();
                            String showProduction = rcvLinesDTO.getShowProductionDate();
                            String showExpired = rcvLinesDTO.getShowExpiredDate();
                            if (StringUtils.isBlank(lotNum) || StringUtils.isBlank(showProduction)
                                    || StringUtils.isBlank(showExpired)) {
                                continue;
                            }
                        }

                        String batchId = rcvLinesDTO.getBatchId();
                        if (StringUtils.isBlank(batchId)) {
                            continue;
                        }
                        InvStockBatchNumberUpdate ibnu = new InvStockBatchNumberUpdate();
                        ibnu.setBatchExpiredDate(rcvLinesDTO.getBatchExpiredDate());
                        ibnu.setBatchProductionDate(rcvLinesDTO.getBatchExpiredDate());
                        ibnu.setManufacturerLotNum(rcvLinesDTO.getManufacturerLotNum());
                        ibnu.setBatchId(batchId);
                        // 显示日期格式字段 TODO
                        ibnu.setBatchProductionDateShow(rcvLinesDTO.getShowProductionDate());
                        ibnu.setBatchExpiredDateShow(rcvLinesDTO.getShowExpiredDate());
                        batchNumbers.add(ibnu);
                    }
                    if (!ObjectUtils.isNull(batchNumbers)) {
                        baseInventoryRemoteCaller.updateBatchNumber(batchNumbers);
                    }

                    // 更新其他批次的信息 TODO
                    excuteUpdateOtherBatchInfo(value);
                } else if (key == 0) {
                    List<RcvLinesDTO> needGen = new ArrayList<>();
                    for (RcvLinesDTO rcvLinesDTO : value) {
                        String stockStatus = rcvLinesDTO.getStockStatus();
                        if (BizConstant.REJECT.equals(stockStatus)) {
                            String lotNum = rcvLinesDTO.getManufacturerLotNum();
                            String showProduction = rcvLinesDTO.getShowProductionDate();
                            String showExpired = rcvLinesDTO.getShowExpiredDate();
                            if (StringUtils.isBlank(lotNum) || StringUtils.isBlank(showProduction)
                                    || StringUtils.isBlank(showExpired)) {
                                continue;
                            }
                        }
                        needGen.add(rcvLinesDTO);

                    }
                    if (!ObjectUtils.isNull(needGen)) {
                        // 批号插入
                        ValidList<InvStockBatchNumber> invStockBatchNumberList = new ValidList<InvStockBatchNumber>();
                        excuteBuildGetBatchIdCondition(rcvHeadersDTO, rcvType, needGen, invStockBatchNumberList, now);
                        // Step2.1: 错误处理以及获取返回值 (会报错,库存服务,唯一约束)
                        excuteGenBatchId(invStockBatchNumberList, needGen);
                    }

                } else {
                    // 不变 不处理
                    List<RcvLinesDTO> needGen = new ArrayList<>();
                    for (RcvLinesDTO rcvLinesDTO : value) {
                        String stockStatus = rcvLinesDTO.getStockStatus();
                        if (BizConstant.REJECT.equals(stockStatus)) {
                            String lotNum = rcvLinesDTO.getManufacturerLotNum();
                            String showProduction = rcvLinesDTO.getShowProductionDate();
                            String showExpired = rcvLinesDTO.getShowExpiredDate();
                            if (StringUtils.isBlank(lotNum) || StringUtils.isBlank(showProduction)
                                    || StringUtils.isBlank(showExpired)) {
                                continue;
                            }
                        }
                        needGen.add(rcvLinesDTO);
                    }
                    if (!ObjectUtils.isNull(needGen)) {
                        // 需要判断当前批号是否存在
                        boolean flag = needGen.stream().anyMatch(p -> StringUtils.isBlank(p.getBatchId()));
                        if (flag) {
                            throw new BizException("批次id为空(batchId),请检查自己的批次信息!");
                        }

                        obj = vaildateBatchInfo(rcvHeadersDTO, rcvType, needGen);
                    }
                }

            }
        } else {
            // 默认处理
            List<RcvLinesDTO> needGen = new ArrayList<>();
            for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
                String stockStatus = rcvLinesDTO.getStockStatus();
                if (BizConstant.REJECT.equals(stockStatus)) {
                    String lotNum = rcvLinesDTO.getManufacturerLotNum();
                    String showProduction = rcvLinesDTO.getShowProductionDate();
                    String showExpired = rcvLinesDTO.getShowExpiredDate();
                    if (StringUtils.isBlank(lotNum) || StringUtils.isBlank(showProduction)
                            || StringUtils.isBlank(showExpired)) {
                        continue;
                    }
                }
                needGen.add(rcvLinesDTO);
            }
            if (!ObjectUtils.isNull(needGen)) {
                obj = vaildateBatchInfo(rcvHeadersDTO, rcvType, needGen);
            }
        }
        return obj;
    }

    private Object vaildateBatchInfo2(RcvHeadersDTO rcvHeadersDTO, String rcvType, List<RcvLinesDTO> value) {
        Object obj = null;
        if (!StringUtils.isBlank(rcvType) && (rcvType.equals(BizConstant.SALE_RETURN_IN)
                || rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN) || rcvType.equals(BizConstant.BLANK_RETURN_IN)
                || rcvType.equals(BizConstant.MOVE_IN) || rcvType.equals(BizConstant.ALLOT_IN))) {
            if (enableVaildateBatchInfo2Web) {
                // 根据配置抛错给前端处理
                Set<String> itemIds = value.stream().map(RcvLinesDTO::getItemId).collect(Collectors.toSet());
                Set<String> batchIds = value.stream().map(RcvLinesDTO::getBatchId).collect(Collectors.toSet());
                Set<String> manufacturerLotNums = value.stream().map(RcvLinesDTO::getManufacturerLotNum)
                        .collect(Collectors.toSet());
                Map<String, Object> queryMap = new HashMap<>();
                queryMap.put("batchIds", batchIds);
                queryMap.put("itemIds", itemIds);
                queryMap.put("manufacturerLotNums", manufacturerLotNums);
//				String warehouseId = rcvHeadersDTO.getWarehouseId();
//				// 仓库
//				queryMap.put("warehouseId", warehouseId);
                String mtlOwnerId = rcvHeadersDTO.getMtlOwnerId();
                // 货主
                queryMap.put("cargoOwnerId", mtlOwnerId);
                List<Map> searchForMap2 = null;
                try {
                    searchForMap2 = searchApi.searchForMap("getBatchInfo", queryMap);
                } catch (Exception e1) {
                    logger.info("找寻商品批次信息失败,原因{}", e1);
                    if (!enableErrorGenBatchInfo) {
                        throw new BizException("找寻商品批次信息失败,调用查询服务,请联系管理员检查!");
                    }
                }
                if (!ObjectUtils.isNull(searchForMap2)) {
                    // 匹配入库已有批次和wms已存在的批次
                    return matchBatchInfo(searchForMap2, value);

                } else {
                    logger.info("找寻商品批次信息为空!请联系管理员检查!");
                    if (!enableErrorGenBatchInfo) {
                        throw new BizException("找寻商品批次信息为空!请联系管理员检查!");
                    }
                }

            } else {
                // 默认缺批次就生成批次
                Set<RcvLinesDTO> res = new HashSet<>();
                Map<String, List<RcvLinesDTO>> collect3 = value.stream()
                        .collect(Collectors.groupingBy(RcvLinesDTO::getBatchId));
                if (ObjectUtils.isNull(collect3)) {
                    res.addAll(value);
                } else {
                    for (List<RcvLinesDTO> rcvLinesDTOlist : collect3.values()) {
                        RcvLinesDTO rcvLinesDTO = rcvLinesDTOlist.get(0);
                        if (rcvLinesDTO != null) {
                            String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
                            String showExpiredDate = rcvLinesDTO.getShowExpiredDate();
                            String showProductionDate = rcvLinesDTO.getShowProductionDate();
                            String itemId = rcvLinesDTO.getItemId();
                            String batchId = rcvLinesDTO.getBatchId();
                            Set<String> set = new HashSet<>();
                            if (!StringUtils.isBlank(batchId)) {
                                set.add(batchId);
                            }
                            Set<String> set2 = new HashSet<>();
                            Set<String> set3 = new HashSet<>();
                            set2.add(itemId);
                            set3.add(manufacturerLotNum);
                            Map<String, Object> queryMap = new HashMap<>();
                            queryMap.put("batchIds", set);
                            queryMap.put("itemIds", set2);
                            queryMap.put("manufacturerLotNums", set3);
                            queryMap.put("showProductionDate", showProductionDate);
                            queryMap.put("showExpiredDate", showExpiredDate);
                            String mtlOwnerId = rcvHeadersDTO.getMtlOwnerId();
                            // 货主
                            queryMap.put("cargoOwnerId", mtlOwnerId);

                            String format = String.format(
                                    "商品id[%s],批次id[%s],批号[%s],生产日期[%s],有效期至[%s],商品批次信息表中不存在,请检查后联系管理员处理!", itemId,
                                    batchId, manufacturerLotNum, showProductionDate, showExpiredDate);
                            List<Map> searchForMap = null;
                            try {
                                searchForMap = searchApi.searchForMap("getBatchInfo", queryMap);
                            } catch (Exception e1) {
                                logger.info(format + "找寻商品批次信息失败,原因{}", e1);
                                if (!enableErrorGenBatchInfo) {
                                    throw new BizException(format);
                                }
                            }
                            if (!ObjectUtils.isNull(searchForMap)) {
                                boolean updateFlag = true;
                                for (Map map : searchForMap) {
                                    // 如果batchId匹配成功,则不发生改变
                                    String batchId2 = (String) map.get("batchId");
                                    String itemId2 = (String) map.get("itemId");
                                    if (!StringUtils.isBlank(batchId) && batchId2.equals(batchId)) {
                                        String showProductionDate2 = (String) map.get("showProductionDate");
                                        String showExpiredDate2 = (String) map.get("showExpiredDate");
                                        String manufacturerLotNum2 = (String) map.get("manufacturerLotNum");
                                        if (!StringUtils.isBlank(manufacturerLotNum2)
                                                && !StringUtils.isBlank(showProductionDate2)
                                                && !StringUtils.isBlank(showExpiredDate2)
                                                && !StringUtils.isBlank(itemId2) && itemId.equals(itemId2)
                                                && manufacturerLotNum2.equals(manufacturerLotNum)
                                                && showProductionDate2.equals(showProductionDate)
                                                && showExpiredDate2.equals(showExpiredDate)) {
                                            updateFlag = false;
                                        }

                                    }
                                }
                                // 需要更新batchId,batchNum
                                if (updateFlag) {
                                    Map map = searchForMap.get(0);
                                    if (!ObjectUtils.isNull(map)) {
                                        String batchId2 = (String) map.get("batchId");
                                        String itemId2 = (String) map.get("itemId");
                                        String batchNum = (String) map.get("batchNum");
                                        String manufacturerLotNum2 = (String) map.get("manufacturerLotNum");
                                        String showProductionDate2 = (String) map.get("showProductionDate");
                                        String showExpiredDate2 = (String) map.get("showExpiredDate");
                                        if (!StringUtils.isBlank(manufacturerLotNum2)
                                                && !StringUtils.isBlank(showProductionDate2)
                                                && !StringUtils.isBlank(showExpiredDate2)
                                                && !StringUtils.isBlank(itemId2) && itemId.equals(itemId2)
                                                && manufacturerLotNum2.equals(manufacturerLotNum)
                                                && showProductionDate2.equals(showProductionDate)
                                                && showExpiredDate2.equals(showExpiredDate)) {
                                            for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOlist) {
                                                rcvLinesDTO2.setBatchId(batchId2);
                                                rcvLinesDTO2.setBatchNum(batchNum);
//												rcvLinesDTO2.setManufacturerLotNum(manufacturerLotNum2);
//												rcvLinesDTO2.setShowProductionDate(showProductionDate2);
//												rcvLinesDTO2.setShowExpiredDate(showExpiredDate2);
                                                // 操作日期格式
                                                excuteHandleDate(rcvLinesDTO2, map);
                                                // 更新收货行
                                                this.mapper.updateMapById(rcvLinesDTO2.getRcvLineId(), MapUtils
//														.put("batchProductionDate", rcvLinesDTO2.getBatchProductionDate())
//														.put("batchExpiredDate", rcvLinesDTO2.getBatchExpiredDate())
                                                                .put("batchId", batchId2).put("batchNum", batchNum).getMap(),
                                                        RcvLines.class);

                                            }
                                        } else {
                                            res.addAll(rcvLinesDTOlist);
                                        }

                                    } else {
                                        logger.info(format);
                                        if (!enableErrorGenBatchInfo) {
                                            throw new BizException(format);
                                        }
                                    }
                                }

                            } else {
                                logger.info(format);
                                if (!enableErrorGenBatchInfo) {
                                    throw new BizException(format);
                                }
                                res.addAll(rcvLinesDTOlist);
                            }
                        }
                    }
                }

                if (enableErrorGenBatchInfo && !ObjectUtils.isNull(res)) {
                    if (!ObjectUtils.isNull(res)) {
                        List<RcvLinesDTO> collect4 = res.stream().distinct().collect(Collectors.toList());
                        ValidList<InvStockBatchNumber> invStockBatchNumberList = new ValidList<InvStockBatchNumber>();
                        excuteBuildGetBatchIdCondition(rcvHeadersDTO, rcvType, collect4, invStockBatchNumberList,
                                new Date());
                        // Step2.1: 错误处理以及获取返回值 (会报错,库存服务,唯一约束)
                        excuteGenBatchId(invStockBatchNumberList, collect4);
                    }
                }
            }
        }
        return obj;
    }

    /**
     * 匹配erp给的批次信息
     *
     * @param searchForMap2
     * @param value
     * @return
     */
    private Object matchBatchInfo(List<Map> searchForMap2, List<RcvLinesDTO> value) {
        Map<String, List<Map>> collect = searchForMap2.stream()
                .filter(p -> !StringUtils.isBlank((String) p.get("itemId"))
                        && !StringUtils.isBlank((String) p.get("manufacturerLotNum")))
                .collect(Collectors.groupingBy(p -> (String) p.get("itemId") + (String) p.get("manufacturerLotNum")));
        Map<Object, Object> res = new HashMap<>();

        for (RcvLinesDTO rcvLinesDTO : value) {
            Integer lineNum = rcvLinesDTO.getLineNum();
            String itemNum = rcvLinesDTO.getItemNum();
            String itemName = rcvLinesDTO.getItemName();
            String itemId = rcvLinesDTO.getItemId();
            String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
            String showProductionDate = rcvLinesDTO.getShowProductionDate();
            String showExpiredDate = rcvLinesDTO.getShowExpiredDate();
            List<Map> list = collect.get(itemId + manufacturerLotNum);
            if (!ObjectUtils.isNull(list)) {
                for (Map map : list) {
                    String batchId = (String) map.get("batchId");
                    String batchNum = (String) map.get("batchNum");
                    String itemId2 = (String) map.get("itemId");
                    String manufacturerLotNum2 = (String) map.get("manufacturerLotNum");
                    String showProductionDate2 = (String) map.get("showProductionDate");
                    String showExpiredDate2 = (String) map.get("showExpiredDate");
                    if (itemId.equals(itemId2) && manufacturerLotNum.equals(manufacturerLotNum2)
                            && showProductionDate.equals(showProductionDate2)
                            && showExpiredDate.equals(showExpiredDate2)) {
                        // 匹配成功
                        rcvLinesDTO.setBatchId(batchId);
                        rcvLinesDTO.setBatchNum(batchNum);
                        // 操作日期格式
                        excuteHandleDate(rcvLinesDTO, map);
                        this.mapper.updateMapById(rcvLinesDTO.getRcvLineId(),
                                MapUtils.put("batchId", batchId).put("batchNum", batchNum)
                                        .put("batchProductionDate", rcvLinesDTO.getBatchProductionDate())
                                        .put("batchExpiredDate", rcvLinesDTO.getBatchExpiredDate()).getMap(),
                                RcvLines.class);
                        break;
                    } else {
                        // 没能匹配
                        res.put(String.valueOf(lineNum), String.format(
                                "收货明细第[%d]行,商品[%s],批号[%s],所属生产日期[%s],有效期至[%s]匹配不成功!存在其他生产日期[%s],有效期至[%s],是否重新生成批次信息?或者尝试使用商品批次调整此批号.",
                                lineNum, itemNum + "-" + itemName, manufacturerLotNum, showProductionDate,
                                showExpiredDate, showProductionDate2, showExpiredDate2));
                        return res;
                    }
                }

            } else {
                res.put(String.valueOf(lineNum),
                        String.format("收货明细第[%d]行,商品[%s],批号[%s],生产日期[%s],有效期至[%s],在wms系统中不存在!是否重新生成?", lineNum,
                                itemNum + "-" + itemName, manufacturerLotNum, showProductionDate, showExpiredDate));
                return res;
            }
        }
        return null;
    }

    private void excuteHandleDate(RcvLinesDTO rcvLinesDTO2, Map map) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        SimpleDateFormat sdf1 = new SimpleDateFormat("yyyyMMdd");
        SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyMM");

        String showProductionDate2 = (String) map.get("showProductionDate");
        String showExpiredDate2 = (String) map.get("showExpiredDate");

        Object productionDateObj = map.get("productionDate");
        Object expiredDateObj = map.get("expiredDate");
        Date productionDate = null;
        if (productionDateObj != null) {
            if (productionDateObj instanceof java.util.Date) {
                productionDate = (Date) productionDateObj;
            }
            if (productionDateObj instanceof Long) {
                Long productionDateL = (Long) productionDateObj;
                productionDate = new Date(productionDateL);
            }
            if (productionDateObj instanceof String) {
                String productionDateStr = (String) productionDateObj;
                try {
                    productionDate = sdf.parse(productionDateStr);
                } catch (ParseException e1) {
                    e1.printStackTrace();
                }
            }
        }
        Date expiredDate = null;
        if (expiredDateObj != null) {
            if (expiredDateObj instanceof java.util.Date) {
                expiredDate = (Date) expiredDateObj;
            }
            if (expiredDateObj instanceof Long) {
                Long expiredDateL = (Long) expiredDateObj;
                expiredDate = new Date(expiredDateL);
            }
            if (expiredDateObj instanceof String) {
                String expiredDateStr = (String) expiredDateObj;
                try {
                    expiredDate = sdf.parse(expiredDateStr);
                } catch (ParseException e1) {
                    e1.printStackTrace();
                }
            }
        }

        Date date = new Date();
        if (productionDate == null) {
            if (StringUtils.isBlank(showProductionDate2)) {
                Date parse1 = null;
                if ("*".equals(showProductionDate2)) {
                    date.setHours(0);
                    date.setMinutes(0);
                    date.setSeconds(0);
                    parse1 = date;
                } else if (showProductionDate2.length() == 6) {
                    try {
                        parse1 = sdf2.parse(showProductionDate2);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                } else if (showProductionDate2.length() == 8) {
                    try {
                        parse1 = sdf1.parse(showProductionDate2);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                if (parse1 == null) {
                    parse1 = date;
                }
                productionDate = parse1;
            }
        }
        if (expiredDate == null) {
            if (StringUtils.isBlank(showExpiredDate2)) {
                Date parse = null;
                if ("*".equals(showExpiredDate2)) {
                    try {
                        parse = sdf1.parse("20990101");
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                } else if (showExpiredDate2.length() == 6) {
                    try {
                        parse = sdf2.parse(showExpiredDate2);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }

                } else if (showExpiredDate2.length() == 8) {
                    try {
                        parse = sdf1.parse(showExpiredDate2);
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }
                if (parse == null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(date);// 设置起时间
                    cal.add(Calendar.YEAR, 100);// 增加100年
                    parse = cal.getTime();
                }
                expiredDate = parse;
            }
        }
        rcvLinesDTO2.setBatchProductionDate(productionDate);
        rcvLinesDTO2.setBatchExpiredDate(expiredDate);

    }

    private Object vaildateBatchInfo(RcvHeadersDTO rcvHeadersDTO, String rcvType, List<RcvLinesDTO> value) {
        return vaildateBatchInfo2(rcvHeadersDTO, rcvType, value);
//		if (!StringUtils.isBlank(rcvType) && (rcvType.equals(BizConstant.SALE_RETURN_IN)
//				|| rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN) || rcvType.equals(BizConstant.BLANK_RETURN_IN))) {
//			Map<String, List<RcvLinesDTO>> collect3 = value.stream()
//					.collect(Collectors.groupingBy(RcvLinesDTO::getBatchId));
//			Set<String> collect2 = value.stream().map(RcvLinesDTO::getBatchId).collect(Collectors.toSet());
//			Map<String, Object> queryMap = new HashMap<>();
//			if (ObjectUtils.isNull(collect2)) {
//				throw new BizException("批次信息为空!请联系管理员检查!");
//			}
//			queryMap.put("batchIds", collect2);
//			List<Map> searchForMap = null;
//			try {
//				searchForMap = searchApi.searchForMap("getBatchInfo", queryMap);
//			} catch (Exception e1) {
//				logger.info("找寻商品批次信息失败,原因{}", e1);
//			}
//			List<RcvLinesDTO> res = new ArrayList<>();
//			if (!ObjectUtils.isNull(searchForMap)) {
//				for (Map smap : searchForMap) {
//					String batchId = (String) smap.get("batchId");
//					boolean contains = collect2.contains(batchId);
//					if (!contains) {
//						List<RcvLinesDTO> list = collect3.get(batchId);
//						String manufacturerLotNum = "";
//						String showExpiredDate = "";
//						String showProductionDate = "";
//						String itemId = "";
//						if (!ObjectUtils.isNull(list)) {
//							RcvLinesDTO rcvLinesDTO = list.get(0);
//							manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
//							showExpiredDate = rcvLinesDTO.getShowExpiredDate();
//							showProductionDate = rcvLinesDTO.getShowProductionDate();
//							itemId = rcvLinesDTO.getItemId();
//						}
//						String format = String.format(
//								"商品id[%s],批次id[%s],批号[%s],生产日期[%s],有效期至[%s],商品批次信息表中不存在,请检查后联系管理员处理!", itemId, batchId,
//								manufacturerLotNum, showProductionDate, showExpiredDate);
//						logger.info(format);
//						throw new BizException(format);
//						// 记录此收货行数据
////						List<RcvLinesDTO> list = collect3.get(batchId);
////						if (!ObjectUtils.isNull(list)) {
////							res.addAll(list);
////						}
//					}
//				}
//			} else {
//				throw new BizException("获取的批次信息为空!请联系管理员检查.参数" + collect2.toString());
//			}
//			// 生成批次数据
////			if (!ObjectUtils.isNull(res)) {
////				List<RcvLinesDTO> collect4 = res.stream().distinct().collect(Collectors.toList());
////				ValidList<InvStockBatchNumber> invStockBatchNumberList = new ValidList<InvStockBatchNumber>();
////				excuteBuildGetBatchIdCondition(rcvHeadersDTO, rcvType, collect4, invStockBatchNumberList, now);
////				// Step2.1: 错误处理以及获取返回值 (会报错,库存服务,唯一约束)
////				excuteGenBatchId(invStockBatchNumberList, value);
////			}
//		}

    }

    private void excuteUpdateOtherBatchInfo(List<RcvLinesDTO> value) {
//		Set<String> batchIds = value.stream().filter(p -> StringUtils.isBlank(p.getBatchId())).map(p -> p.getBatchId())
//				.collect(Collectors.toSet());
        // 操作其它拥有批次信息的表 暂不处理 TODO

    }

    private void excuteGenBatchId(ValidList<InvStockBatchNumber> invStockBatchNumberList,
                                  List<RcvLinesDTO> rcvLinesDTOList) {

        RestMessage<List<InvStockBatchNumberResult>> genBatchNumber = null;
        List<InvStockBatchNumberResult> data = excuteHandlerRemoteError(invStockBatchNumberList, genBatchNumber);
        AssertUtils.isNotEmpty(data, "生成的批次信息为空!");

        Map<String, List<InvStockBatchNumberResult>> collect2 = Optional.ofNullable(data)
                .orElse(Collections.emptyList()).stream().filter(p -> !StringUtils.isBlank(p.getRcvLineId()))
                .collect(Collectors.groupingBy(InvStockBatchNumberResult::getRcvLineId));
        // Step3: 更新收货行的batchNum,batchId
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            String rcvLineId = rcvLinesDTO.getRcvLineId();
            List<InvStockBatchNumberResult> list = collect2.get(rcvLineId);
            if (!ObjectUtils.isNull(list)) {
                InvStockBatchNumberResult invStockBatchNumberResult = list.get(0);
                String batchId = invStockBatchNumberResult.getBatchId();
                String batchNum = invStockBatchNumberResult.getBatchNum();
                this.mapper.updateMapById(rcvLineId,
                        MapUtils.put("batchId", batchId).put("batchNum", batchNum).getMap(), RcvLines.class);
                rcvLinesDTO.setBatchId(batchId);
                rcvLinesDTO.setBatchNum(batchNum);
            }

        }

    }

    private List<InvStockBatchNumberResult> excuteHandlerRemoteError(
            ValidList<InvStockBatchNumber> invStockBatchNumberList,
            RestMessage<List<InvStockBatchNumberResult>> genBatchNumber) {
        if (ObjectUtils.isNull(invStockBatchNumberList)) {
            return null;
        }
        try {
            // logger.info("调用库存接口genBatchNumber，入参："+
            // JsonUtils.toString(invStockBatchNumberList));
            logger.info("调用库存接口genBatchNumber，入参：" + JsonUtils.toString(invStockBatchNumberList));
            genBatchNumber = baseInventoryRemoteCaller.genBatchNumber(invStockBatchNumberList);
            if (genBatchNumber != null) {
                logger.info("返回结果：" + JsonUtils.toString(genBatchNumber));
            }
        } catch (Exception e) {
            logger.error("调用远程生成批次信息出现错误错误!", e);
            throw new BizException("调用远程库存服务生成批次信息错误!请联系管理员处理!");
        }
        if (genBatchNumber == null)
            throw new BizException("远程调用库存服务获取数据为空!请联系管理员处理!");

        if (genBatchNumber.isSuccess() && genBatchNumber.getData() == null)
            throw new BizException("生成批次信息为空!请联系管理员处理!");

        if (!genBatchNumber.isSuccess()) {
            if (!ObjectUtils.isNull(genBatchNumber.getData())) {
                throw new BizException("远程调用库存服务错误!原因->" + genBatchNumber.getMessage() + genBatchNumber.getData());
            } else {
                throw new BizException("远程调用库存服务错误!原因->" + genBatchNumber.getMessage());
            }

        }

        List<InvStockBatchNumberResult> data = genBatchNumber.getData();
        return data;
    }

    private void excuteBuildGetBatchIdCondition(RcvHeadersDTO rcvHeadersDTO, String rcvType,
                                                List<RcvLinesDTO> rcvLinesDTOList, ValidList<InvStockBatchNumber> invStockBatchNumberList, Date now) {
        String asnHeaderId = rcvHeadersDTO.getAsnHeaderId();
        Date rcvDate = rcvHeadersDTO.getRcvDate();
        String mtlOwnerId = rcvHeadersDTO.getMtlOwnerId();
        String vendorId = rcvHeadersDTO.getVendorId();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            InvStockBatchNumber result = new InvStockBatchNumber();
            Date batchExpiredDate = rcvLinesDTO.getBatchExpiredDate();
            Date batchProductionDate = rcvLinesDTO.getBatchProductionDate();
            String erpBatchNum = rcvLinesDTO.getErpBatchNum();
            String itemId = rcvLinesDTO.getItemId();
            String manufacturerLotNum = rcvLinesDTO.getManufacturerLotNum();
            String orgId = rcvLinesDTO.getOrgId();
            BigDecimal piecePriceTe = rcvLinesDTO.getPiecePriceTe();
            BigDecimal piecePriceTi = rcvLinesDTO.getPiecePriceTi();
            String productionPlace = rcvLinesDTO.getProductionPlace();
            BigDecimal shelfLifeDays = rcvLinesDTO.getShelfLifeDays();
            BigDecimal taxRate = rcvLinesDTO.getTaxRate();
            if (null == piecePriceTe)
                piecePriceTe = BigDecimal.ZERO; // 不含税
            if (null == piecePriceTi)
                piecePriceTi = BigDecimal.ZERO; // 含税
            // 税率 = (含税-不含税)/不含税
            if (null == taxRate && BigDecimal.ZERO.compareTo(piecePriceTe) != 0)
                taxRate = (piecePriceTe.subtract(piecePriceTe)).divide(piecePriceTe, 4, RoundingMode.HALF_UP);
            if (null == taxRate)
                taxRate = BigDecimal.ONE;
            String vendorBatchNum = rcvLinesDTO.getVendorBatchNum();
            String rcvLineId = rcvLinesDTO.getRcvLineId();

            // 需要加入批次id的处理 TODO

            result.setRcvLineId(rcvLineId);
            result.setAsnId(asnHeaderId);
            result.setBatchExpiredDate(batchExpiredDate);
            result.setBatchProductionDate(batchProductionDate);
            result.setCargoOwnerId(mtlOwnerId);
            result.setErpBatchNum(erpBatchNum);
            result.setGradeId("9");
            result.setItemId(itemId);
            result.setManufacturerLotNum(manufacturerLotNum);
            result.setOrgnId(orgId);
            result.setPieceCostTe(piecePriceTe);
            result.setPieceCostTi(piecePriceTi);
            result.setProductionPlace(productionPlace);
            result.setRcvDate(rcvDate);
            if (shelfLifeDays != null) {
                result.setShelfLifeDays(shelfLifeDays);
            } else {
                result.setShelfLifeDays(BigDecimal.valueOf(90));
            }
            result.setTaxRate(taxRate);
            result.setVendorBatchNum(vendorBatchNum);
            result.setVendorId(vendorId);
            String showProductionDate = rcvLinesDTO.getShowProductionDate();
            String showExpiredDate = rcvLinesDTO.getShowExpiredDate();
            if (StringUtils.isBlank(showProductionDate)) {
                showProductionDate = sdf.format(batchProductionDate);
            }
            if (StringUtils.isBlank(showExpiredDate)) {
                showExpiredDate = sdf.format(batchExpiredDate);
            }
            result.setBatchProductionDateShow(showProductionDate);
            result.setBatchExpiredDateShow(showExpiredDate);
            invStockBatchNumberList.add(result);
        }
    }

    /**
     * 处理批号,以及校验数据
     *
     * @param rcvType
     * @param rcvLinesDTOList
     * @param now
     * @param userDTO
     */
    private void excuteHandlerLotNum(String rcvType, List<RcvLinesDTO> rcvLinesDTOList, Date now, UserDTO userDTO) {
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        int row = 0;
        String enterpriseId = userDTO.getEnterpriseId();
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            row++;
            Integer lineNum = rcvLinesDTO.getLineNum();
            if (lineNum == null) {
                rcvLinesDTO.setLineNum(row);
            }
            String inventoryOpType = rcvLinesDTO.getInventoryOpType();
            if (!StringUtils.isBlank(inventoryOpType)) {
                rcvLinesDTO.setEditFlag(2);
            }

            String stockStatus = rcvLinesDTO.getStockStatus();
            if (BizConstant.REJECT.equals(stockStatus)) {
                String lotNum = rcvLinesDTO.getManufacturerLotNum();
                String showProduction = rcvLinesDTO.getShowProductionDate();
                String showExpired = rcvLinesDTO.getShowExpiredDate();
                if (StringUtils.isBlank(lotNum) || StringUtils.isBlank(showProduction)
                        || StringUtils.isBlank(showExpired)) {
                    continue;
                }
            }

            String showExpiredDate2 = rcvLinesDTO.getShowExpiredDate();
            String showProductionDate2 = rcvLinesDTO.getShowProductionDate();
            if (StringUtils.isBlank(showProductionDate2)) {
                rcvLinesDTO.setShowProductionDate("*");
            }
            if (StringUtils.isBlank(showExpiredDate2)) {
                rcvLinesDTO.setShowExpiredDate("*");
            }
            // 校验日期格式
            String showExpiredDate = rcvLinesDTO.getShowExpiredDate();
            String showProductionDate = rcvLinesDTO.getShowProductionDate();
            if (StringUtils.isBlank(showExpiredDate) || StringUtils.isBlank(showProductionDate)) {
                throw new BizException(String.format("第[%d]行,显示生产日期或显示有效期至为空!请检查!", row));
            }

//			if (StringUtils.isBlank(showExpiredDate) || !showExpiredDate.equals("*")
//					|| ObjectUtils.isValidDate(showExpiredDate)) {
//				throw new BizException(String.format("第[%d]行,请检查有效期至格式是否正确!", row));
//			}
//			if (StringUtils.isBlank(showProductionDate) || !showProductionDate.equals("*")
//					|| ObjectUtils.isValidDate(showProductionDate)) {
//				throw new BizException(String.format("第[%d]行,请检查生产日期格式是否正确!", row));
//			}
            // 校验冷藏字段 (应当根据存储条件来校验)
//			RcvLinesProfilesDTO rcvLinesProfilesDTO = rcvLinesDTO.getRcvLinesProfilesDTO();
//			AssertUtils.notNull(rcvLinesProfilesDTO, "收货行的拓展信息为空!");
//			String storeTemperature = rcvLinesProfilesDTO.getStoreTemperature();
//			if (!StringUtils.isBlank(storeTemperature) && storeTemperature.contains("冷")
//					&& ObjectUtils.isNull(rcvLinesDTO.getRcvLinesPicDTOList())) {
//				throw new BizException(String.format("第[%d]行,请检查自己的冷藏品图片数据是否上传!", row));
//			}
//			String categoryName = rcvLinesDTO.getCategoryName();
//			if (!StringUtils.isBlank(categoryName) && categoryName.contains("冷")
//					&& ObjectUtils.isNull(rcvLinesDTO.getRcvLinesPicDTOList())) {
//				throw new BizException(String.format("第[%d]行,请检查自己的冷藏品图片数据是否上传!", row));
//			}
            // 数据准确性计算
            BigDecimal pieceQty = rcvLinesDTO.getPieceQty();
            BigDecimal conversionRate = rcvLinesDTO.getConversionRate();
            if (conversionRate == null) {
                conversionRate = BigDecimal.ONE;
                rcvLinesDTO.setConversionRate(conversionRate);
            }
            if (pieceQty == null) {
                pieceQty = BigDecimal.ZERO;
                rcvLinesDTO.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); // 包装总量
            // 保证数据正确性再次进行计算
            rcvLinesDTO.setOddCaseQty(caseQty);
            rcvLinesDTO.setOddPieceQty(oddPieceQty);
            rcvLinesDTO.setQty(qty);
//			if (rcvType.equals(BizConstant.PURCHASE_IN)) {
            // 普通采购入库处理
            // 批号判断 为*或空增加当前时间100年
            if (rcvLinesDTO.getManufacturerLotNum().equals("*") || "".equals(rcvLinesDTO.getManufacturerLotNum())) {
                rcvLinesDTO.setManufacturerLotNum("*");
                Date batchExpiredDate = rcvLinesDTO.getBatchExpiredDate();
                Date batchProductionDate = rcvLinesDTO.getBatchProductionDate();
                if (null == batchExpiredDate || null == batchProductionDate) {
                    // 日期归零
                    Date date = now;
                    date.setHours(0);
                    date.setMinutes(0);
                    date.setSeconds(0);
//						Calendar cal = Calendar.getInstance();
//						cal.setTime(date);// 设置起时间
//						cal.add(Calendar.YEAR, 100);// 增加100年
//						// 默认 2099-01-01
//						Date time = cal.getTime();
                    Date parse = null;
                    try {
                        parse = dateFormat.parse("2099-01-01");
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                    rcvLinesDTO.setBatchProductionDate(date);
                    rcvLinesDTO.setBatchExpiredDate(parse);
                }
            }
//			}
            if (rcvType.equals(BizConstant.SALE_RETURN_IN)) {

            }
            if (rcvType.equals(BizConstant.ALLOT_IN)) {

            }
            if (rcvType.equals(BizConstant.MOVE_IN)) {

            }
            if (rcvType.equals(BizConstant.ACCOUNT_REG_IN)) {

            }
            if (rcvType.equals(BizConstant.OVERSTEP_IN)) {

            }
            if (rcvType.equals(BizConstant.STRAIGHT_IN)) {

            }
            if (rcvType.equals(BizConstant.HOSTED_IN)) {

            }
            if (rcvType.equals(BizConstant.WAIT_CHECK_IN)) {

            }
            if (rcvType.equals(BizConstant.INSTRUMENT_IN)) {

            }
            if (rcvType.equals(BizConstant.FREE_IN)) {

            }
            if (rcvType.equals(BizConstant.BLANK_ENTITY_IN)) {

            }
            if (rcvType.equals(BizConstant.BLANK_IN)) {

            }
            if (rcvType.equals(BizConstant.BLANK_RETURN_ENTITY_IN)) {

            }
            if (rcvType.equals(BizConstant.BLANK_RETURN_IN)) {

            }
//			switch (rcvType) {
//			case BizConstant.PURCHASE_IN:
//				// 普通采购入库处理
//				// 批号判断 为*或空增加当前时间100年
//				if (rcvLinesDTO.getManufacturerLotNum().equals("*") || "".equals(rcvLinesDTO.getManufacturerLotNum())) {
//					rcvLinesDTO.setManufacturerLotNum("*");
//					Date batchExpiredDate = rcvLinesDTO.getBatchExpiredDate();
//					Date batchProductionDate = rcvLinesDTO.getBatchProductionDate();
//					if (null == batchExpiredDate || null == batchProductionDate) {
//						// 日期归零
//						Date date = now;
//						date.setHours(0);
//						date.setMinutes(0);
//						date.setSeconds(0);
////						Calendar cal = Calendar.getInstance();
////						cal.setTime(date);// 设置起时间
////						cal.add(Calendar.YEAR, 100);// 增加100年
////						// 默认 2099-01-01
////						Date time = cal.getTime();
//						Date parse = null;
//						try {
//							parse = dateFormat.parse("2099-01-01");
//						} catch (ParseException e) {
//							e.printStackTrace();
//						}
//						rcvLinesDTO.setBatchProductionDate(date);
//						rcvLinesDTO.setBatchExpiredDate(parse);
//					}
//				}
//				break;
//			case BizConstant.SALE_RETURN_IN:
//				// 销售退回
//
//				break;
//			case BizConstant.ALLOT_IN:
//
//				break;
//			case BizConstant.MOVE_IN:
//
//				break;
//			case BizConstant.ACCOUNT_REG_IN:
//
//				break;
//			case BizConstant.OVERSTEP_IN:
//
//				break;
//			case BizConstant.STRAIGHT_IN:
//
//				break;
//			case BizConstant.HOSTED_IN:
//
//				break;
//			case BizConstant.WAIT_CHECK_IN:
//
//				break;
//			case BizConstant.INSTRUMENT_IN:
//
//				break;
//			case BizConstant.FREE_IN:
//
//				break;
//			case BizConstant.BLANK_ENTITY_IN:
//
//				break;
//			case BizConstant.BLANK_IN:
//
//				break;
//			case BizConstant.BLANK_RETURN_ENTITY_IN:
//
//				break;
//			case BizConstant.BLANK_RETURN_IN:
//
//				break;
//
//			default:
//				break;
//			}
            // 显示生产日期,有效期至为*号的处理
            Date date = now;
            if ("*".equals(showProductionDate)) {
                date.setHours(0);
                date.setMinutes(0);
                date.setSeconds(0);
                rcvLinesDTO.setBatchProductionDate(date);
            }
            if ("*".equals(showExpiredDate)) {
                Date parse = null;
                try {
                    parse = dateFormat.parse("2099-01-01");
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                if (parse == null) {
                    Calendar cal = Calendar.getInstance();
                    cal.setTime(date);// 设置起时间
                    cal.add(Calendar.YEAR, 100);// 增加100年
                    parse = cal.getTime();
                }
                rcvLinesDTO.setBatchExpiredDate(parse);
            }

            // 生产日期,效期,时分秒归零
            Date batchExpiredDate = rcvLinesDTO.getBatchExpiredDate();
            Date batchProductionDate = rcvLinesDTO.getBatchProductionDate();
            if (batchExpiredDate == null || batchProductionDate == null) {
                throw new BizException(String.format("第[%d]行,日期格式的生产日期或有效期至为空!请检查!", row));
            }

            batchExpiredDate.setHours(0);
            batchExpiredDate.setMinutes(0);
            batchExpiredDate.setSeconds(0);
            rcvLinesDTO.setBatchExpiredDate(batchExpiredDate);
            batchProductionDate.setHours(0);
            batchProductionDate.setMinutes(0);
            batchProductionDate.setSeconds(0);
            rcvLinesDTO.setBatchProductionDate(batchProductionDate);

//			// 校验批号信息是否重复
//			RcvLineLotInfo rcvLineLotInfo = new RcvLineLotInfo();
//			BeanUtils.copyProperties(rcvLinesDTO, rcvLineLotInfo);
//			rcvLineLotInfo.setEnterpriseId(enterpriseId);
//			excuteVaildateRcvItemLotNum(rcvLineLotInfo, row);

            String batchId = rcvLinesDTO.getBatchId();
            if (StringUtils.isBlank(batchId)) {
                rcvLinesDTO.setBatchId(rcvLinesDTO.getBatchNum());
            }
        }
    }

    private Object saleReturnBatchAdd(List<RcvLinesDTO> rcvLinesDTOList, String masterId, UserDTO userDTO,
                                      String mtlOwnerId, String warehouseId, CargoChangeIn cargoChangeIn) {
        // 执行销售退回的逻辑
        logger.info("开始执行销售退回的逻辑!");
        // Step1:校验asn单的行的明细剩余量是否大于0 asn数量-已收货数量-已拒收数量(已在循环中实现)
//		excuteVaildatePieceExceed(rcvLinesDTOList);

        if (null == userDTO)
            userDTO = userUtils.getUserDTO();
        int i = 0;
        boolean editFlag = Boolean.FALSE;
        Date now = new Date();
        String enterpriseId = userDTO.getEnterpriseId();
        StringBuilder sb = new StringBuilder();
        boolean b = rcvLinesDTOList.stream().anyMatch(x -> x.getIsRetrospect() == 1);
        Boolean isLock = false;
        if(b){
            Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
            Restriction r1 = Restrictions.eq("refBillId", rcvLinesDTOList.get(0).getAsnHeaderId());
            Restriction r2 = Restrictions.eq("unlock", 1);
            Restriction r3 = Restrictions.and(r1,r2);
            criteria1.setRestriction(r3);
            long countByCriteria = mapper.findCountByCriteria(criteria1);
            if(countByCriteria>0){
                isLock = true;
            }
        }
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
            i++;
            // 校验容器
            vaildateContainerCode(rcvLinesDTO, i);
            // 头表id
            rcvLinesDTO.setRcvHeaderId(masterId);
            // 构建默认字段
            this.buildDefaultField(rcvLinesDTO, editFlag, userDTO);
            // 校验基础数据
            this.vaildateModel(rcvLinesDTO, editFlag, userDTO, i, validator, "保存的收货行操作");
            RcvLines lines = new RcvLines();
            BeanUtils.copyProperties(rcvLinesDTO, lines);
            // 设置系统级字段
            super.setBaseSysField(lines, editFlag, userDTO, now);
            // 校验数据库重复
            this.vaildateModelRepeated(lines, editFlag, userDTO);

//			vaildateLotInfo(rcvLinesDTO, i);

            String stockStatus = rcvLinesDTO.getStockStatus();
            if (!StringUtils.isBlank(stockStatus) && stockStatus.equals(BizConstant.REJECT)) {

            } else {
                Date batchExpiredDate = rcvLinesDTO.getBatchExpiredDate();
                Long subtract = DateUtils.subtract(now, batchExpiredDate, ChronoUnit.DAYS);

                // 近效期提示
                if (subtract <= expiredDays) {
                    // 记录提示的消息
                    String format = String.format("第[%d]行数据还有[%d]天过期,请注意!\r\n", i, subtract);
                    sb.append(format);
                }
                if (subtract <= 0) {
                    // 过期处理,入不合格库
//                    rcvLinesDTO.setWhAreaCategoryCode("THK");
                    lines.setItemHealthIsDouble(0); // 不进行双人质检
                }
            }

            lines.setMtlOwnerId(mtlOwnerId);
            lines.setWarehouseId(warehouseId);
            Integer itemHealthIsDouble = lines.getItemHealthIsDouble();
            if (itemHealthIsDouble == null) {
                lines.setItemHealthIsDouble(0); // 默认单人质检
            }
            if(!StringUtils.isEmpty(rcvLinesDTO.getItemHealthType())){
                lines.setAttribute1(rcvLinesDTO.getItemHealthType());
            }

            if(!StringUtils.isEmpty(rcvLinesDTO.getLocNo())){
                lines.setAttribute2(rcvLinesDTO.getLocNo());
            }
            // 保存收货行数据,校验数量是否超出(并发考虑)
            excuteSaveLine(lines, enterpriseId, i);
            rcvLinesDTO.setRcvLineId(lines.getRcvLineId());
            // 保存拓展数据
            excuteSaveOthers(rcvLinesDTO, lines, userDTO, i);

            try {
                excuteSavePic(rcvLinesDTO, lines, userDTO, i);
            } catch (Exception e) {
                e.printStackTrace();
            }
            //校验监管码更新监管码为收货单纬度
            if(rcvLinesDTO.getIsRetrospect()==1){
                Criteria criteria = Criteria.forClass(SupervisionCode.class);
                criteria.restrictionBuilder().eq("refBillId",rcvLinesDTO.getAsnHeaderId())
                        .eq("refBillLineId",rcvLinesDTO.getRefAsnLineId())
                        .eq("creator",userDTO.getId());
                criteria.buildRestriction();
                List<SupervisionCode> supervisionCodeList = supervisionCodeMapper.findByCriteria(criteria);
                if(isLock){
                    if(CollectionUtil.isNotEmpty(supervisionCodeList)){
                        String[] ids = supervisionCodeList.stream().map(x -> x.getId()).toArray(String[]::new);
                        criteria = Criteria.forClass(SupervisionCode.class);
                        criteria.restrictionBuilder().in("id",ids);
                        criteria.buildRestriction();
                        supervisionCodeMapper.updateMapByCriteria(MapUtils.put("refBillId",lines.getRcvHeaderId()).put("refBillLineId",lines.getRcvLineId())
                                .put("manufacturerLotNum",rcvLinesDTO.getManufacturerLotNum())
                                        .put("productionDate",rcvLinesDTO.getBatchProductionDate()).put("expiredDate",rcvLinesDTO.getBatchExpiredDate()).getMap(),criteria);
                    }
                }else{
                    if(CollectionUtil.isEmpty(supervisionCodeList)){
                        throw new BizException(String.format("第%d行请扫描监管码",i));
                    }
                    BigDecimal reduce = supervisionCodeList.stream().map(x -> new BigDecimal(x.getPackSize())).reduce(BigDecimal.ZERO, BigDecimal::add);
                    if(reduce.compareTo(rcvLinesDTO.getPieceQty())!=0){
                        throw new BizException(String.format("第%d行收货数量与监管码数量不一致",i));
                    }
                    String[] ids = supervisionCodeList.stream().map(x -> x.getId()).toArray(String[]::new);
                    criteria = Criteria.forClass(SupervisionCode.class);
                    criteria.restrictionBuilder().in("id",ids);
                    criteria.buildRestriction();
                    supervisionCodeMapper.updateMapByCriteria(MapUtils.put("refBillId",lines.getRcvHeaderId()).put("refBillLineId",lines.getRcvLineId())
                            .put("manufacturerLotNum",rcvLinesDTO.getManufacturerLotNum())
                                    .put("productionDate",rcvLinesDTO.getBatchProductionDate()).put("expiredDate",rcvLinesDTO.getBatchExpiredDate()).getMap(),criteria);
                }
            }
        }
        return sb;
    }

    private void excuteVaildatePieceExceed(List<RcvLinesDTO> rcvLinesDTOList) {
        Map<String, List<RcvLinesDTO>> collect = rcvLinesDTOList.stream()
                .filter(p -> !StringUtils.isBlank(p.getAsnLineId()))
                .collect(Collectors.groupingBy(RcvLinesDTO::getAsnLineId));
        Map<String, BigDecimal> asnMap = new HashMap<>();
        for (Map.Entry<String, List<RcvLinesDTO>> entry : collect.entrySet()) {
            String key = entry.getKey();
            List<RcvLinesDTO> value = entry.getValue();
            BigDecimal reduce = Optional.ofNullable(value).orElse(Collections.emptyList()).stream()
                    .map(RcvLinesDTO::getPieceQty).reduce(BigDecimal.ZERO, BigDecimal::add);
            asnMap.put(key, reduce);
        }
        // 根据asn分组计算收货的总量然后和原剩余比对,防止多收,前端也可校验
        this.vaildatePieceExceed(asnMap);

    }

    private void excuteSaveLineList(Map<String, BigDecimal> asnMap, List<RcvLines> saveData) {
        this.mapper.saveBatch(saveData);
        // 根据asn分组计算收货的总量然后和原剩余比对,防止多收,前端也可校验
        this.vaildatePieceExceed(asnMap);

    }

    private void vaildatePieceExceed(Map<String, BigDecimal> asnMap) {
        // 校验数量是否超出原asn行的数据
        // TODO
        logger.info("开始比对asn行的数量,防止多收!");
        if (ObjectUtils.isNull(asnMap))
            return;

        List<String> asnLineList = asnMap.entrySet().stream().map(p -> p.getKey()).collect(Collectors.toList());
        // 根据asn列表查询asn的剩余量
        if (ObjectUtils.isNull(asnLineList))
            return;
        String[] array = asnLineList.toArray(new String[asnLineList.size()]);
        // 暂时本地调用asnDetail TODO 以后远程或者用presto调用
        OmsAsnBillDQueryVO vo = new OmsAsnBillDQueryVO();
        vo.setLineids(asnLineList);
        List<Map<String, Object>> queryOmsAsnBillDRemainQtyMap = omsAsnBillHService.queryOmsAsnBillDRemainQty(vo);
        if (ObjectUtils.isNull(queryOmsAsnBillDRemainQtyMap))
            return;

        // 计算逻辑
        for (Map<String, Object> map : queryOmsAsnBillDRemainQtyMap) {
            String lineid = (String) map.get("lineid");
            BigDecimal bigDecimal = asnMap.get(lineid);
            if (null == bigDecimal)
                continue;
            BigDecimal remainQty = (BigDecimal) map.get("remainQty");
            if (remainQty.compareTo(bigDecimal) == -1) {
                // 日期超出报错
                String format = String.format("asnLineid为[%s]的数量已经超出,超出数量[%d]", lineid, remainQty.doubleValue());
                logger.info(format);
                throw new BizException(format);
            }
        }
    }
//	@Override
//	@Transactional
//	public Object batchAdd(List<RcvLinesDTO> rcvLinesDTOList, String masterId, UserDTO userDTO, String mtlOwnerId,
//			String warehouseId) {
//		if (null == userDTO)
//			userDTO = userUtils.getUserDTO();
//		int i = 0;
//		boolean editFlag = Boolean.FALSE;
//		Date now = new Date();
//		String enterpriseId = userDTO.getEnterpriseId();
//		// 这里先使用模拟的默认字段z
//		Integer doubleCheckFlag = new Random().nextInt(2); // 随机0和1 单人0双人1
//		for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList) {
//			i++;
//
//			// 头表id
//			rcvLinesDTO.setRcvHeaderId(masterId);
//			// 构建默认字段
//			this.buildDefaultField(rcvLinesDTO, editFlag, userDTO);
//			// 校验基础数据
//			this.vaildateModel(rcvLinesDTO, editFlag, userDTO, i, validator, "保存的收货行操作");
//			RcvLines lines = new RcvLines();
//			BeanUtils.copyProperties(rcvLinesDTO, lines);
//			// 设置系统级字段
//			super.setBaseSysField(lines, editFlag, userDTO, now);
//			// 校验数据库重复
//			this.vaildateModelRepeated(lines, editFlag, userDTO);
//			lines.setMtlOwnerId(mtlOwnerId);
//			lines.setWarehouseId(warehouseId);
//			lines.setItemHealthIsDouble(doubleCheckFlag);
//			// 批号判断 为*或空增加当前时间100年
//			if (lines.getManufacturerLotNum().equals("*") || "".equals(lines.getManufacturerLotNum())) {
//				Calendar cal = Calendar.getInstance();
//				cal.setTime(now);// 设置起时间
//				cal.add(Calendar.YEAR, 100);// 增加100年
//				Date time = cal.getTime();
//				lines.setBatchProductionDate(now);
//				lines.setBatchExpiredDate(time);
//				// TODO 回传oms 为* 时间
//			}
//			// 校验效期 90天内
//			Date batchProductionDate = lines.getBatchProductionDate();
//			if (batchProductionDate.before(now)
//					&& expiredDays < DateUtils.subtract(batchProductionDate, now, ChronoUnit.DAYS)) {
//				// TODO 回传到OMS 审核状态 如要收货 需先录入异常信息回传到OMS审核后再收货
//				// 给予提示
//				throw new BizException(String.format("警告!第%d行数据录入有问题,商品近效期小于%d天.", i, expiredDays));
//
//			}
//
//			// 保存收货行数据,校验数量是否超出(并发考虑)
//			excuteSaveLine(lines, enterpriseId, i);
//
//			rcvLinesDTO.setRcvLineId(lines.getRcvLineId());
//			excuteSaveOthers(rcvLinesDTO, lines, userDTO, i);
//		}
//		// 根据结论退不同的任务池,可考虑是否异步
//		Map<String, List<RcvLinesDTO>> collect = Optional.ofNullable(rcvLinesDTOList).orElse(Collections.emptyList())
//				.stream().distinct().collect(Collectors.groupingBy(RcvLinesDTO::getStockStatus));
//		AssertUtils.notNull(collect, "收货行数据根据收货结论分组为空!");
//
//		RcvTypeStrategyEnum rcvTypeStrategyEnum = taskHelper.getRcvTypeStrategyEnum(masterId);
//		RqcStrategyEnum rqcStrategyEnum = taskHelper.getRqcStrategyEnum(masterId);
//
//		for (List<RcvLinesDTO> rcvLinesDTO : collect.values()) {
//
//			String rcvStockStatus = rcvLinesDTO.get(0).getStockStatus();
//			// 调用策略工厂来组织执行器执行任务
//			RcvSubjectFactory factory = new RcvSubjectFactoryS1Impl();
//			Map<String, Object> map = new HashedMap<>();
//			map.put("data", rcvLinesDTO);
//			map.put("mtlOwnerId", mtlOwnerId);
//			map.put("warehouseId", warehouseId);
//			ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(rcvStockStatus);
//			factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum);
//		}
//		return true;
//	}
//	
//	@Override
//	public Object recommendArea(List<RcvLinesDTO> rcvLinesDTOList) {
//		if (ObjectUtils.isNull(rcvLinesDTOList))
//			return null;
//		// 获取推荐的库别/库区code集合
//		RcvLinesDTO rcvLinesDTO = rcvLinesDTOList.get(0);
//		String mtlOwnerId = rcvLinesDTO.getMtlOwnerId();
//		String warehouseId = rcvLinesDTO.getWarehouseId();
//		String enterpriseId = userUtils.getEnterpriseId();
//		// Step1: 远程找寻策略
//		RestMessage<StrategyDTO> strategyResult = strategyClient.getStrategyDTO(enterpriseId, "ReceiveCargo",
//				mtlOwnerId, warehouseId);
//		if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null)
//			throw new BizException("未找到有效的策略");
//		StrategyDTO strategyDTO = strategyResult.getData();
//		Strategy strategy = null;
//		try {
//			strategy = strategyDTO.createStrategy();
//		} catch (IllegalAccessException | InstantiationException | ClassNotFoundException e) {
//			// 打印日志
//			logger.error("策略创建失败,原因->", e);
//		}
//		// Step2: 获取具体策略
//		if (ObjectUtils.isNotNull(strategy)) {
//			for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOList) {
//				// 组装匹配因子
//				WhAreaCategoryContext context = new WhAreaCategoryContext();
//				WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();
//				
//				String rcvType = rcvLinesDTO2.getRcvType(); // 单据类型
//				rcvLineData.setBillType(rcvType);
//				
////				String itemIsPieceOrCase = rcvLinesDTO2.getItemIsPieceOrCase();
////				if (StringUtils.isBlank(itemIsPieceOrCase))
////					itemIsPieceOrCase = "1"; // 默认整散分开
////				if (itemIsPieceOrCase.equals("1"))
////					rcvLineData.setIsPieceOrCase(false);
////				else
////					rcvLineData.setIsPieceOrCase(true);
////				// 判断数据的整散
////				BigDecimal oddPieceQty = rcvLinesDTO2.getOddPieceQty();
////				BigDecimal oddCaseQty = rcvLinesDTO2.getOddCaseQty();
////				if (null != oddPieceQty && oddPieceQty.compareTo(BigDecimal.ZERO) == 0)
////					// 为整数
////					rcvLineData.setIsCase("0");
////				if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 0 && null != oddPieceQty
////						&& oddPieceQty.compareTo(BigDecimal.ZERO) == 1)
////					// 零散散
////					rcvLineData.setIsCase("1");
////				if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 1 && null != oddPieceQty
////						&& oddPieceQty.compareTo(BigDecimal.ZERO) == 1)
////					// 整散
////					rcvLineData.setIsCase("2");
//				try {
//					strategy.execute(context); // 捕捉异常
//				} catch (StrategyExecuteException e) {
//					logger.error("策略执行失败,原因->", e);
//					e.printStackTrace();
//				}
//				
//				Boolean flag = true;
//				while (flag) {
//					boolean completed = context.completed();
//					if (completed) {
//						flag = false;
//						List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
//						System.out.println(targetAreaCategoryCodes);
//					}
//				}
//				
//			}
//		}
//		return null;
//	}

    /**
     * 校验批号信息
     */
    @Override
    public Object excuteVaildateRcvItemLotNum(RcvLineLotInfo rcvLineLotInfo, int row) {
        String manufacturerLotNum = rcvLineLotInfo.getManufacturerLotNum();
        AssertUtils.isNotBlank(manufacturerLotNum, "批号不可为空!");
        String itemId = rcvLineLotInfo.getItemId();
        String mtlOwnerId = rcvLineLotInfo.getMtlOwnerId();
        String warehouseId = rcvLineLotInfo.getWarehouseId();
        String enterpriseId = rcvLineLotInfo.getEnterpriseId();
        String showExpiredDate2 = rcvLineLotInfo.getShowExpiredDate();
        String showProductionDate2 = rcvLineLotInfo.getShowProductionDate();
        AssertUtils.isNotBlank(itemId, "商品id不可为空!");
        AssertUtils.isNotBlank(mtlOwnerId, "货主id不可为空!");
        AssertUtils.isNotBlank(warehouseId, "仓库id不可为空!");
        AssertUtils.isNotBlank(showExpiredDate2, "显示有效期至不可为空!");
        AssertUtils.isNotBlank(showProductionDate2, "显示生产日期不可为空!");
        if (StringUtils.isBlank(enterpriseId)) {
            enterpriseId = userUtils.getEnterpriseId();
        }
        if ("*".equals(manufacturerLotNum))
            return true; // 为*号时的处理
        Criteria crt = Criteria.forClass(RcvLines.class);
        Restriction eq = Restrictions.eq("manufacturerLotNum", manufacturerLotNum);
        Restriction eq2 = Restrictions.eq("itemId", itemId);
        Restriction eq3 = Restrictions.eq("mtlOwnerId", mtlOwnerId);
        Restriction eq4 = Restrictions.eq("warehouseId", warehouseId);
        Restriction eq5 = Restrictions.eq("enterpriseId", enterpriseId);
        Restriction and = Restrictions.and(eq, eq2, eq3, eq4, eq5);
        crt.setRestriction(and);
        List<RcvLines> findByCriteria = this.mapper.findByCriteria(crt);
        if (ObjectUtils.isNull(findByCriteria))
            return true;
        RcvLines rcvLines = findByCriteria.get(0);
        String showExpiredDate = rcvLines.getShowExpiredDate();
        String showProductionDate = rcvLines.getShowProductionDate();
        Date batchExpiredDate = rcvLines.getBatchExpiredDate();
        Date batchProductionDate = rcvLines.getBatchProductionDate();
        String format = String.format("第[%d]行,批号[%s]重复,已存在批号,生产日期为[%s],有效期至为[%s],请使用新批号,或使用已有的生产日期,有效期至", row,
                manufacturerLotNum, showProductionDate, showExpiredDate);
        if (!StringUtils.isBlank(showExpiredDate) && !showExpiredDate.equals(showExpiredDate2)
                && !StringUtils.isBlank(showProductionDate) && !showProductionDate.equals(showProductionDate2)) {
            throw new BizException(format);
        }
        return true;
    }

    private void vaildateQty(List<RcvLinesDTO> rcvLinesDTOList) {
        // TODO Auto-generated method stub
    }

    /**
     * 校验容器
     */
    @Override
    public Object vaildateContainer(List<RcvLinesDTO> rcvLinesDTOList) {
        AssertUtils.isNotEmpty(rcvLinesDTOList, "校验的收货集合为空!请检查!");
        Set<String> containerCodes = rcvLinesDTOList.stream().filter(p -> !StringUtils.isBlank(p.getContainerCode()))
                .map(RcvLinesDTO::getContainerCode).collect(Collectors.toSet());
        if (ObjectUtils.isNull(containerCodes)) {
            return null;
        }
        ContainerQueryVO cQueryVO = new ContainerQueryVO();
        cQueryVO.setContainerCodeList(new ArrayList<>(containerCodes));
        RestMessage<Object> batchVaildateEnable = null;
        try {
            batchVaildateEnable = baseWmsWarehouseCaller.batchVaildateEnable(cQueryVO);
        } catch (Exception e) {
            logger.error("调用库存服务校验容器的可用性出错,原因->{}", e.getMessage());
        }
        if (batchVaildateEnable == null || !batchVaildateEnable.isSuccess()) {
            logger.info("调用库存服务校验容器的可用性服务错误,原因->{}",
                    batchVaildateEnable == null ? "" : batchVaildateEnable.getMessage());
        }
        if (batchVaildateEnable.getData() != null && !(Boolean) batchVaildateEnable.getData()) {
            throw new BizException("请检查自己容器是否可用!");
        }
        // 托盘容器：不同药品大类、不同存储分类（整散分开、整散合一、不同收货结论（收货、待处理）、整件和散件等容器分开收货；
        Map<String, List<RcvLinesDTO>> collect = rcvLinesDTOList.stream()
                .filter(p -> !StringUtils.isBlank(p.getContainerCode()))
                .collect(Collectors.groupingBy(RcvLinesDTO::getContainerCode));
        for (List<RcvLinesDTO> rcvLinesDTOList2 : collect.values()) {
            String containerCode = rcvLinesDTOList2.get(0).getContainerCode();
            excuteVaildateContainerCode(rcvLinesDTOList2, containerCode);
        }
        return null;
    }

    private void excuteVaildateContainerCode(List<RcvLinesDTO> rcvLinesDTOList2, String containerCode) {
        Set<String> itemCategoryCodeSet = new HashSet<>();
        Set<String> stockStatusSet = new HashSet<>();
        Set<String> storeTemperatureSet = new HashSet<>();
        Set<String> caseOrPieceSet = new HashSet<>();
        for (RcvLinesDTO rcvLinesDTO : rcvLinesDTOList2) {
            String itemCategoryCode = rcvLinesDTO.getCategoryId();
            String stockStatus = rcvLinesDTO.getStockStatus();
            RcvLinesProfilesDTO rcvLinesProfilesDTO = rcvLinesDTO.getRcvLinesProfilesDTO();
            String storeTemperature = rcvLinesProfilesDTO.getStoreTemperature();
            String caseOrPiece = getCaseOrPiece(rcvLinesDTO);
            itemCategoryCodeSet.add(itemCategoryCode);
            stockStatusSet.add(stockStatus);
            storeTemperatureSet.add(storeTemperature);
            caseOrPieceSet.add(caseOrPiece);
        }
        if (!ObjectUtils.isNull(itemCategoryCodeSet) && itemCategoryCodeSet.size() > 1) {
            throw new BizException(String.format("容器号[%s],存在不相同的商品大类,请检查!", containerCode));
        }
        if (!ObjectUtils.isNull(stockStatusSet) && stockStatusSet.size() > 1) {
            throw new BizException(String.format("容器号[%s],存在不相同的收货结论,请检查!", containerCode));
        }
        if (!ObjectUtils.isNull(storeTemperatureSet) && storeTemperatureSet.size() > 1) {
            throw new BizException(String.format("容器号[%s],存在不相同的储存条件,请检查!", containerCode));
        }
        if (!ObjectUtils.isNull(caseOrPieceSet) && caseOrPieceSet.size() > 1) {
            throw new BizException(String.format("容器号[%s],存在整散混在一起,请检查!", containerCode));
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    public Object recommendArea(List<RcvLinesDTO> rcvLinesDTOList) {
        // 这里策略总是执行失败,缺数据
        try {
            logger.info(String.format("收货策略请求参数[%s]", JsonUtils.toString(rcvLinesDTOList)));
        } catch (JsonProcessingException e2) {
            e2.printStackTrace();
        }

        if (ObjectUtils.isNull(rcvLinesDTOList))
            return rcvLinesDTOList;
        // 获取推荐的库别/库区code集合
        RcvLinesDTO rcvLinesDTO = rcvLinesDTOList.get(0);
        if (rcvLinesDTO == null) {
            return rcvLinesDTOList;
        }
        String mtlOwnerId = rcvLinesDTO.getMtlOwnerId();
        String warehouseId = rcvLinesDTO.getWarehouseId();
        String enterpriseId = userUtils.getEnterpriseId();
        // Step1: 远程找寻策略
        RestMessage<StrategyDTO> strategyResult = null;
        try {
            strategyResult = strategyClient.getStrategyDTO(enterpriseId, "ReceiveCargo", mtlOwnerId, warehouseId);
        } catch (Exception e1) {
            // 避免强制报错
            e1.printStackTrace();
            return rcvLinesDTOList;
        }
        if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null)
//			throw new BizException("未找到有效的策略");
            return rcvLinesDTOList;
        StrategyDTO strategyDTO = strategyResult.getData();
        Strategy strategy = null;
        try {
            strategy = strategyDTO.createStrategy();
        } catch (Exception e) {
            // 打印日志
            logger.info("策略创建失败,原因->", e);
            return rcvLinesDTOList;
        }
        // Step2: 获取具体策略
        Date now = new Date();
        int row = 0;
        if (ObjectUtils.isNotNull(strategy)) {
            row++;
            for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOList) {
                // 组装匹配因子
                WhAreaCategoryContext context = new WhAreaCategoryContext();
                WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();

                String rcvType = rcvLinesDTO2.getRcvType(); // 单据类型
                rcvLineData.setBillType(rcvType);
                Date batchExpiredDate = rcvLinesDTO2.getBatchExpiredDate();
                if (batchExpiredDate != null && batchExpiredDate.before(now)) {
                    rcvLineData.setIsExpiry(true);
                } else {
                    rcvLineData.setIsExpiry(false);
                }

                context.setRcvLineData(rcvLineData);

                try {
                    logger.info(String.format("收货策略执行参数[%s]", JsonUtils.toString(context)));
                    strategy.execute(context); // 捕捉异常
                } catch (Exception e) {
//				} catch (StrategyExecuteException  e) {
                    logger.info("策略执行失败,原因->", e);
                    e.printStackTrace();
                    return rcvLinesDTOList;
                }
                boolean completed = context.completed();
                if (completed) {
                    // 找到匹配的策略
                    List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
                    String join = "";
                    if (!ObjectUtils.isNull(targetAreaCategoryCodes)) {
                        join = String.join(",", targetAreaCategoryCodes);
                    }
                    rcvLinesDTO2.setWarehouseAreaCategorys(join);
                    Integer lineNum = rcvLinesDTO2.getLineNum();
                    if (lineNum == null)
                        lineNum = row;

                    logger.info(String.format("第[%d]行,推荐库别[%s]", lineNum, join));
                }
            }
            Set<String> categorySet = new HashSet<>();
            for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOList) {
                String warehouseAreaCategorys = rcvLinesDTO2.getWarehouseAreaCategorys();
                List<String> asList = null;
                if (!StringUtils.isBlank(warehouseAreaCategorys)) {
                    String[] category = warehouseAreaCategorys.split(",");
                    if (category != null && category.length > 0) {
                        asList = Arrays.asList(category);
                    }
                    if (!ObjectUtils.isNull(asList)) {
                        categorySet.addAll(asList);
                    }
                }
            }
            if (ObjectUtils.isNull(categorySet))
                return rcvLinesDTOList;

            WarehouseAreaQueryVO areaQueryVO = new WarehouseAreaQueryVO();
            areaQueryVO.setEnterpriseId(enterpriseId);
            List<String> categoryList = new ArrayList<String>(categorySet);
            areaQueryVO.setWarehouseAreaCategoryList(categoryList);
            areaQueryVO.setWarehouseId(warehouseId);

            // 组装库区集合
            RestMessage<Object> listSimpleInfo = null;
            try {
                listSimpleInfo = baseWmsWarehouseCaller.listSimpleInfo(areaQueryVO);
            } catch (Exception e) {
                // 避免远程调用抛错
                e.printStackTrace();
                return rcvLinesDTOList;
            }
            if (listSimpleInfo == null || !listSimpleInfo.isSuccess() || listSimpleInfo.getData() == null)
//				throw new BizException("未找到库区信息");
                return rcvLinesDTOList;
            List<Map<String, Object>> areaData = (List<Map<String, Object>>) listSimpleInfo.getData();

            Map<String, List<Map<String, Object>>> collect = (Map<String, List<Map<String, Object>>>) Optional
                    .ofNullable(areaData).orElse(Collections.EMPTY_LIST).stream().filter(p -> filter(p))
                    .collect(Collectors.groupingBy(p -> fetch(p)));
            if (ObjectUtils.isNull(collect)) {
                return rcvLinesDTOList;
            }
            for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTOList) {
                String warehouseAreaCategorys = rcvLinesDTO2.getWarehouseAreaCategorys();
                if (StringUtils.isBlank(warehouseAreaCategorys)) {
                    continue;
                }
                String[] split = warehouseAreaCategorys.split(",");
                Set<String> areaCodeSet = new HashSet<>();
                Set<String> roomCodeSet = new HashSet<>();
                for (String sp : split) {
                    List<Map<String, Object>> list = collect.get(sp);
                    if (ObjectUtils.isNotNull(list)) {
                        for (Map<String, Object> map : list) {
                            String warehouseAreaCode = (String) map.get("warehouseAreaCode");
                            if (!StringUtils.isBlank(warehouseAreaCode)) {
                                areaCodeSet.add(warehouseAreaCode);
                            }
                            // 操作库房集合
                            String warehouseRoomCode = (String) map.get("warehouseRoomCode");
                            if (!StringUtils.isBlank(warehouseRoomCode)) {
                                roomCodeSet.add(warehouseRoomCode);
                            }
                        }
                    }
                }
                if (ObjectUtils.isNotNull(areaCodeSet)) {
                    String join2 = String.join(",", areaCodeSet);
                    rcvLinesDTO2.setWarehouseAreaCodes(join2);
                }
                if (ObjectUtils.isNotNull(roomCodeSet)) {
                    String join3 = String.join(",", roomCodeSet);
                    rcvLinesDTO2.setWarehouseRoomCodes(join3);
                }
            }
        }
        /* 获取托盘码放规则----on 2022-08-04---by 陈浩 开始 */
        Set<String> itemIdsArr = rcvLinesDTOList.stream().filter(p -> !StringUtils.isBlank(p.getItemId()))
                .map(RcvLinesDTO::getItemId).collect(Collectors.toSet());
        RestMessage<List<BaseMtlItemMst>> itemResult = null;
        if (itemIdsArr != null && itemIdsArr.size() > 0) {
            itemResult = itemClient.getListByIds(itemIdsArr);
        }
        itemResult.getData().stream().forEach(f -> {
            RcvLinesDTO dto = rcvLinesDTOList.stream().filter(m -> m.getItemId().equals(f.getItemId())).findFirst()
                    .orElse(null);
            if (dto != null) {
                dto.setPalletPlacedRule(f.getBaseMtlItemWms().getPalletPlacedRule());
            }
        });
        /* 获取托盘码放规则----on 2022-08-04---by 陈浩 结束 */
        return rcvLinesDTOList;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<RcvCommonLine> getConclusion(List<RcvCommonLine> rcvCommonLineList) {
        if (ObjectUtils.isNull(rcvCommonLineList)) {
            return rcvCommonLineList;
        }
        try {
            logger.info(String.format("结论策略请求参数[%s]", JsonUtils.toString(rcvCommonLineList)));
        } catch (JsonProcessingException e2) {
            e2.printStackTrace();
        }
        RcvCommonLine rcvCommonLine = rcvCommonLineList.get(0);
        if (rcvCommonLine == null) {
            return rcvCommonLineList;
        }
        List<Map<String, String>> resultList = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        Map<String, String> map2 = new HashMap<>();
        Map<String, String> map3 = new HashMap<>();
        Map<String, String> map4 = new HashMap<>();

        Integer refType = rcvCommonLine.getRefType();
        if (refType == null || refType > 2) {
            // 收货节点的结论和验收节点选择的不一致
            map1.put("code", "0");
            map1.put("name", "收货");
        } else {
            map1.put("code", "0");
            map1.put("name", "合格");
            map2.put("code", "1");
            map2.put("name", "不合格");
            resultList.add(map1);
            resultList.add(map2);
        }
//				0合格/1不合格/2待处理/3拒绝
        map3.put("code", "2");
        map3.put("name", "待处理");
        map4.put("code", "3");
        map4.put("name", "拒收");
        resultList.add(map3);
        resultList.add(map4);

        String mtlOwnerId = rcvCommonLine.getMtlOwnerId();
        String warehouseId = rcvCommonLine.getWarehouseId();
        String enterpriseId = userUtils.getEnterpriseId();

        // Step1: 远程找寻策略
        RestMessage<StrategyDTO> strategyResult = null;
        try {
            strategyResult = strategyClient.getStrategyDTO(enterpriseId,
                    StrategyCategoryEnum.RcvStatusChoose.getValue(), mtlOwnerId, warehouseId);
        } catch (Exception e1) {
            // 避免强制报错
            logger.info("结论策略调用失败,原因=>" + e1.getMessage());
            rcvCommonLineList.stream().forEach(p -> {
                p.setConclusionList(resultList);
            });
            return rcvCommonLineList;
        }
        if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null) {
            rcvCommonLineList.stream().forEach(p -> {
                p.setConclusionList(resultList);
            });
            return rcvCommonLineList;
        }
        StrategyDTO strategyDTO = strategyResult.getData();
        Strategy strategy = null;
        try {
            strategy = strategyDTO.createStrategy();
        } catch (Exception e) {
            // 打印日志
            logger.info("策略创建失败,原因->", e.getMessage());
            rcvCommonLineList.stream().forEach(p -> {
                p.setConclusionList(resultList);
            });
            return rcvCommonLineList;
        }
        // Step2: 获取具体策略
        Date now = new Date();
        int row = 0;
        if (ObjectUtils.isNotNull(strategy)) {
            for (RcvCommonLine line : rcvCommonLineList) {
                row++;
                String refId = line.getRefId();
                // 组装匹配因子
                WhAreaCategoryContext context = new WhAreaCategoryContext();
                WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();

                String rcvType = line.getRcvType();
                AssertUtils.isNotBlank(rcvType, "单据类型不可为空!");
                // 单据类型
                rcvLineData.setBillType(rcvType);
                // 是否过效期
                Date batchExpiredDate = line.getBatchExpiredDate();
//				AssertUtils.isNotNull(batchExpiredDate, String.format("第[%d]行,有效期至不可为空!", row));
                if (batchExpiredDate == null) {
                    rcvLineData.setBillType("0000");
                }
                if (batchExpiredDate != null && batchExpiredDate.before(now)) {
                    rcvLineData.setIsExpiry(true);
                }
                if (batchExpiredDate != null && !batchExpiredDate.before(now)) {
                    rcvLineData.setIsExpiry(false);
                }
                // 数据来源的结论
                rcvLineData.setConclusion(line.getStockStatus());
                // 数据来源
                rcvLineData.setDataSource(line.getRefType() + "");

                context.setRcvLineData(rcvLineData);

                try {
                    logger.info(String.format("收货策略执行参数[%s]", JsonUtils.toString(context)));
                    strategy.execute(context); // 捕捉异常
                } catch (Exception e) {
                    logger.error(String.format("第[%d]行,来源id(refId)[%s],策略执行失败,原因->[%s]", row, refId, e.getMessage()));
                    line.setConclusionList(resultList);
                    continue;
                }
                boolean completed = context.completed();
                if (completed) {
                    // 找到匹配的策略
                    List<String> resultStrategy = context.getTargetAreaCategoryCodes();
                    if (ObjectUtils.isNotNull(resultStrategy)) {
                        logger.info(String.format("第[%d]行,结论选择[%s]", row, resultStrategy.toString()));
                        List<Map<String, String>> resultList2 = new ArrayList<>();
                        for (String str : resultStrategy) {
                            Map<String, String> map = new HashMap<>();
                            if (refType == null || refType > 2) {
                                if (str.equals("0")) {
                                    map.put("code", "0");
                                    map.put("name", "收货");
                                }
                            } else {
                                if (str.equals("0")) {
                                    map.put("code", "0");
                                    map.put("name", "合格");
                                }
                                if (str.equals("1")) {
                                    map.put("code", "1");
                                    map.put("name", "不合格");
                                }
                            }
                            if (str.equals("2")) {
                                map.put("code", "2");
                                map.put("name", "待处理");
                            }
                            if (str.equals("3")) {
                                map.put("code", "3");
                                map.put("name", "拒收");
                            }
                            resultList2.add(map);
                        }
                        line.setConclusionList(resultList2);
                    } else {
                        line.setConclusionList(resultList);
                    }
                } else {
                    line.setConclusionList(resultList);
                }
            }
        } else {
            rcvCommonLineList.stream().forEach(p -> {
                p.setConclusionList(resultList);
            });
        }
        return rcvCommonLineList;
    }

    @Override
    public List<RcvCommonLine> getAreaCategory(List<RcvCommonLine> rcvCommonLineList) {
        return null;
    }

    @Override
    public List<Map<String, String>> getConclusionSingle(RcvCommonLine rcvCommonLine) {
        List<Map<String, String>> resultList = new ArrayList<>();
        Map<String, String> map1 = new HashMap<>();
        Map<String, String> map2 = new HashMap<>();
        Map<String, String> map3 = new HashMap<>();
        Map<String, String> map4 = new HashMap<>();
//		0合格/1不合格/2待处理/3拒绝
        map1.put("code", "0");
        map1.put("name", "合格");
        map2.put("code", "1");
        map2.put("name", "不合格");
        map3.put("code", "2");
        map3.put("name", "待处理");
        map4.put("code", "3");
        map4.put("name", "拒收");
        resultList.add(map1);
        resultList.add(map2);
        resultList.add(map3);
        resultList.add(map4);

        String mtlOwnerId = rcvCommonLine.getMtlOwnerId();
        String warehouseId = rcvCommonLine.getWarehouseId();
        String enterpriseId = userUtils.getEnterpriseId();
        // Step1: 远程找寻策略
        RestMessage<StrategyDTO> strategyResult = null;
        try {
            strategyResult = strategyClient.getStrategyDTO(enterpriseId,
                    StrategyCategoryEnum.RcvStatusChoose.getValue(), mtlOwnerId, warehouseId);
        } catch (Exception e1) {
            // 避免强制报错
            logger.info("结论策略调用失败,原因=>" + e1.getMessage());
            return resultList;
        }

        if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null) {
            return resultList;
        }
        StrategyDTO strategyDTO = strategyResult.getData();
        Strategy strategy = null;
        try {
            strategy = strategyDTO.createStrategy();
        } catch (Exception e) {
            // 打印日志
            logger.info("策略创建失败,原因->", e.getMessage());
            return resultList;
        }

        int row = 1;
        String refId = rcvCommonLine.getRefId();
        // 组装匹配因子
        WhAreaCategoryContext context = new WhAreaCategoryContext();
        WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();

        String rcvType = rcvCommonLine.getRcvType();
        AssertUtils.isNotBlank(rcvType, "单据类型不可为空!");
        // 单据类型
        rcvLineData.setBillType(rcvType);
        // 是否过效期
        Date batchExpiredDate = rcvCommonLine.getBatchExpiredDate();
//		AssertUtils.isNotNull(batchExpiredDate, String.format("第[%d]行,有效期至不可为空!", row));
        if (batchExpiredDate == null) {
            rcvLineData.setBillType("0000");
        }
        Date now = new Date();
        if (batchExpiredDate != null && batchExpiredDate.before(now)) {
            rcvLineData.setIsExpiry(true);
        }
        if (batchExpiredDate != null && !batchExpiredDate.before(now)) {
            rcvLineData.setIsExpiry(false);
        }
        // 数据来源的结论
        rcvLineData.setConclusion(rcvCommonLine.getStockStatus());
        // 数据来源
        rcvLineData.setDataSource(rcvCommonLine.getRefType() + "");

        context.setRcvLineData(rcvLineData);

        try {
            logger.info(String.format("收货策略执行参数[%s]", JsonUtils.toString(context)));
            strategy.execute(context); // 捕捉异常
        } catch (Exception e) {
            logger.error(String.format("第[%d]行,来源id(refId)[%s],策略执行失败,原因->[%s]", row, refId, e.getMessage()));
            rcvCommonLine.setConclusionList(resultList);
        }
        boolean completed = context.completed();
        if (completed) {
            // 找到匹配的策略
            List<String> resultStrategy = context.getTargetAreaCategoryCodes();
            if (ObjectUtils.isNotNull(resultStrategy)) {
                logger.info(String.format("第[%d]行,结论选择[%s]", row, resultStrategy.toString()));
                List<Map<String, String>> resultList2 = new ArrayList<>();
                for (String str : resultStrategy) {
                    Map<String, String> map = new HashMap<>();
                    if (str.equals("0")) {
                        map.put("code", "0");
                        map.put("name", "合格");
                    }
                    if (str.equals("1")) {
                        map.put("code", "1");
                        map.put("name", "不合格");
                    }
                    if (str.equals("2")) {
                        map.put("code", "2");
                        map.put("name", "待处理");
                    }
                    if (str.equals("3")) {
                        map.put("code", "3");
                        map.put("name", "拒收");
                    }
                    resultList2.add(map);
                }
                rcvCommonLine.setConclusionList(resultList2);
            } else {
                rcvCommonLine.setConclusionList(resultList);
            }
        } else {
            rcvCommonLine.setConclusionList(resultList);
        }
        List<Map<String, String>> conclusionList = rcvCommonLine.getConclusionList();
        if (ObjectUtils.isNull(conclusionList)) {
            return resultList;
        }
        return rcvCommonLine.getConclusionList();
    }

    private String getCaseOrPiece(RcvCommonLine target) {
        // 是否整散
        BigDecimal pieceQty = target.getPieceQty();
        BigDecimal conversionRate = target.getConversionRate();
        BigDecimal oddCaseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN);
        BigDecimal oddPieceQty = pieceQty.subtract(oddCaseQty.multiply(conversionRate));
        // 判断数据的整散
        if (null != oddPieceQty && oddPieceQty.compareTo(BigDecimal.ZERO) == 0) {
            // 为整数
            return "0";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 0 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 零散散
            return "1";
        }

        if (null != oddCaseQty && oddCaseQty.compareTo(BigDecimal.ZERO) == 1 && null != oddPieceQty
                && oddPieceQty.compareTo(BigDecimal.ZERO) == 1) {
            // 整散
            return "2";
        }
        return "0";
    }

    @Override
    public RcvCommonLine byConditionToAreaCategory(RcvCommonLine rcvCommonLine) {
        Assert.isFalse(rcvCommonLine == null, "入参不能为空");
        String mtlOwnerId = rcvCommonLine.getMtlOwnerId();
        String warehouseId = rcvCommonLine.getWarehouseId();
        Assert.isFalse(StringUtils.isBlank(mtlOwnerId), "仓id不能为空");
        Assert.isFalse(StringUtils.isBlank(warehouseId), "货主id不能为空");
        try {
            logger.info(String.format("入库库别选择策略获取库别请求参数[%s]", JsonUtils.toString(rcvCommonLine)));
        } catch (JsonProcessingException e2) {
            e2.printStackTrace();
        }

        String enterpriseId = userUtils.getEnterpriseId();
        // Step1: 远程找寻策略
        RestMessage<StrategyDTO> strategyResult = null;
        try {
            strategyResult = strategyClient.getStrategyDTO(enterpriseId,
                    StrategyCategoryEnum.RcvAreaCategoryChoose.getValue(), mtlOwnerId, warehouseId);
        } catch (Exception e1) {
            // 避免强制报错
            logger.info("入库库别选择策略调用失败,原因=>" + e1.getMessage());
            return rcvCommonLine;
        }
        if (strategyResult == null || !strategyResult.isSuccess() || strategyResult.getData() == null) {
            return rcvCommonLine;
        }
        StrategyDTO strategyDTO = strategyResult.getData();
        Strategy strategy = null;
        try {
            strategy = strategyDTO.createStrategy();
        } catch (Exception e) {
            // 打印日志
            logger.info("策略创建失败,原因->", e.getMessage());
            return rcvCommonLine;
        }
        List<BaseMtlItemMst> itemList = null;

        Set<String> itemSet = new HashSet<String>();
        itemSet.add(rcvCommonLine.getItemId());
        if (itemSet != null && itemSet.size() > 0) {
            itemList = new ArrayList<BaseMtlItemMst>();
            RestMessage<List<BaseMtlItemMst>> itemResult = baseItemRemoteCaller.getListByIds(itemSet);
            Assert.isFalse(itemResult == null, "质检验收获取商品信息不存在,请检查");
            if (!itemResult.isSuccess()) {
                throw BizException.newInstance("质检验收获取商品信息" + itemResult.getMessage());
            }
            itemList = itemResult.getData();
        }

        int row = 0;
        List<Map<String, String>> rsultList = new ArrayList<Map<String, String>>();
        Map<String, String> areaMap = BizConstant.getAreaCodeAndNameList();
        if (ObjectUtils.isNotNull(strategy)) {
            row++;
            String refId = rcvCommonLine.getRefId();
            // 组装匹配因子
            WhAreaCategoryContext context = new WhAreaCategoryContext();
            WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();
            BaseMtlItemMst baseMtlItemMst = itemList.stream()
                    .filter(item -> Objects.equals(item.getItemId(), rcvCommonLine.getItemId())).findFirst().orElse(null);

            String rcvType = rcvCommonLine.getRcvType();
            AssertUtils.isNotBlank(rcvType, "单据类型不可为空!");
            // 单据类型
            rcvLineData.setBillType(rcvType);
            // 收货数
            String isCase = getCaseOrPiece(rcvCommonLine);
            rcvLineData.setIsCase(isCase);
            // 收货件数
            rcvLineData.setQty(rcvCommonLine.getConversionRate().doubleValue());
            // 是否异型
//            if (baseMtlItemMst != null && baseMtlItemMst.getBaseMtlItemWms() != null) {
//                Integer abnormal = baseMtlItemMst.getBaseMtlItemWms().getItemIsSpecialSharped();
//                rcvLineData.setStoreTemperature(abnormal.toString());
//            }
            // 数据来源
            rcvLineData.setDataSource(rcvCommonLine.getRefType().toString());
            context.setRcvLineData(rcvLineData);
            try {
                logger.info(String.format("入库收货库别选择策略执行参数[%s]", JsonUtils.toString(context)));
                strategy.execute(context); // 捕捉异常
            } catch (Exception e) {
                logger.error(String.format("第[%d]行,来源id(refId)[%s],策略执行失败,原因->[%s]", row, refId, e.getMessage()));
            }
            boolean completed = context.completed();
            if (completed) {
                // 找到匹配的策略
                List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
                if (ObjectUtils.isNotNull(targetAreaCategoryCodes)) {
                    logger.info(String.format("第[%d]行,结论选择[%s]", row, targetAreaCategoryCodes.toString()));
                    for (String targetAreaCategoryCode : targetAreaCategoryCodes) {
                        Map<String, String> resultMap = new HashMap<String, String>();
                        if (areaMap.containsKey(targetAreaCategoryCode)) {
                            resultMap.put("label", areaMap.get(targetAreaCategoryCode));
                            resultMap.put("value", targetAreaCategoryCode);
                            rsultList.add(resultMap);
                        }
                    }
                }
            }
            rcvCommonLine.setAreaCategoryList(rsultList);
        }
        return rcvCommonLine;
    }
}
