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

import cn.hutool.core.lang.Assert;
import com.codingapi.tx.annotation.TxTransaction;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.prolog.common.util.DateUtils;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.warehouse.model.vo.ContainerQueryVO;
import com.prolog.cs.biz.inbound.constant.BizConstant;
import com.prolog.cs.biz.inbound.constant.OperationConstant;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesMapper;
import com.prolog.cs.biz.inbound.dao.rqc.RqcHeadersMapper;
import com.prolog.cs.biz.inbound.dao.rqc.RqcLinesMapper;
import com.prolog.cs.biz.inbound.dao.task.TaskQcDetailMapper;
import com.prolog.cs.biz.inbound.dto.PageParam;
import com.prolog.cs.biz.inbound.dto.RcvCommonLine;
import com.prolog.cs.biz.inbound.dto.rqc.RcvLineResult;
import com.prolog.cs.biz.inbound.dto.rqc.RqcHeadersDTO;
import com.prolog.cs.biz.inbound.dto.rqc.RqcLinesDTO;
import com.prolog.cs.biz.inbound.dto.task.TaskQcDetailDTO;
import com.prolog.cs.biz.inbound.model.rcv.RcvLines;
import com.prolog.cs.biz.inbound.model.rqc.RqcHeaders;
import com.prolog.cs.biz.inbound.model.rqc.RqcLines;
import com.prolog.cs.biz.inbound.model.task.TaskQcDetail;
import com.prolog.cs.biz.inbound.remote.BaseInventoryRemoteCaller;
import com.prolog.cs.biz.inbound.remote.BaseItemRemoteCaller;
import com.prolog.cs.biz.inbound.remote.BaseWmsWarehouseCaller;
import com.prolog.cs.biz.inbound.remote.StrategyClient;
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.RcvLinesService;
import com.prolog.cs.biz.inbound.service.rqc.RqcLinesService;
import com.prolog.cs.biz.inbound.service.task.TaskQcDetailService;
import com.prolog.cs.biz.inbound.utils.ObjectUtils;
import com.prolog.cs.biz.inbound.utils.UserUtils;
import com.prolog.cs.biz.inbound.vo.RqcDQueryVO;
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.pojo.Page;
import com.prolog.framework.core.restriction.*;
import com.prolog.framework.dao.util.DaoUtils;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.AssertUtils;
import com.prolog.framework.utils.JsonUtils;
import com.prolog.framework.utils.MapUtils;
import com.prolog.framework.utils.StringUtils;
import com.prolog.upcloud.base.inventory.vo.InvStockBatchNumberUpdate;
import com.prolog.upcloud.base.strategy.domain.core.Strategy;
import com.prolog.upcloud.base.strategy.dto.StrategyDTO;
import org.apache.commons.collections.CollectionUtils;
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.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class RqcLinesServiceImpl extends BaseServiceImpl<RqcLines> implements RqcLinesService {

	@Resource
	private RqcLinesMapper mapper;

	@Resource
	private UserUtils userUtils;

	@Resource
	private Validator validator;

	@Resource
	private TaskHelper taskHelper;

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

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

	@Resource
	private TaskQcDetailMapper taskQcDetailMapper;

	@Resource
	private TaskQcDetailService taskQcDetailService;

	@Resource
	private BaseInventoryRemoteCaller baseInventoryRemoteCaller;

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

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

	@Resource
	private RcvLinesMapper rcvLinesMapper;

	@Resource
	private SearchApi searchApi;

	@Resource
	private BaseItemRemoteCaller baseItemRemoteCaller;

	@Resource
	private RcvLinesService rcvLinesService;

	@Resource
	private StrategyClient strategyClient;

	@Resource
	private RqcHeadersMapper rqcHeadersMapper;

	@Resource
	private BaseWmsWarehouseCaller baseWmsWarehouseCaller;

	private final static String SERVICE_MSG = "质检行明细";
	private static Logger logger = LoggerFactory.getLogger(RqcLinesServiceImpl.class);

	private void updateTaskPoolExcuter(List<String> taskIds2) {
		if (ObjectUtils.isNull(taskIds2))
			return;
		// 更新质检池任务状态 为已执行
		Criteria criteria = new Criteria(TaskQcDetail.class);
		criteria.setRestriction(Restrictions.in("taskRqcId", taskIds2.toArray()));
		taskQcDetailMapper.updateExcuterAndTimes(userUtils.getUserName(), taskIds2); // 置为已完成
//		taskQcDetailMapper.updateMapByCriteria(MapUtils.put("executor", userUtils.getUserName()).put("times",1).getMap(), criteria); // 置为已完成
	}

	private void excuteBatchUpdate(List<RqcLinesDTO> list2, UserDTO userDTO) {
		if (ObjectUtils.isNull(list2))
			return;
		// 更新质检数据及其头表信息
		FieldSelector fs = new FieldSelector();
//		String[] includes = { "qcReason1", "qcOpcode1", "qcDate1", "qcResult1","qcStatus1", "times", "modifierName", "modifier",
//				"gmtModified" };handlingSuggestion defReason handlingReason defReasonExt handlingMeasure
		String[] includes = { "rqcHeaderId", "qcReason2", "qcOpcode2", "qcDate2", "qcResult2", "qcStatus2", "times",
				"modifierName", "modifier", "gmtModified", "handlingSuggestion", "defReason", "handlingReason",
				"defReasonExt", "handlingMeasure" };
		fs.include(includes);
		String enterpriseId = userDTO.getEnterpriseId();
		Criteria criteria = new Criteria(RqcLines.class);
		Restriction eq = Restrictions.eq("enterpriseId", enterpriseId);
		Date now = new Date();
        String qcOpcode1 = "";
		String qcOpcode2 = "";
		String rqcHeaderId = "";
		for (RqcLinesDTO rqcLinesDTO : list2) {
			Integer itemHealthIsDouble = rqcLinesDTO.getItemHealthIsDouble();
			if (0 == itemHealthIsDouble)
				continue;

			Restriction eq2 = Restrictions.eq("taskRqcId", rqcLinesDTO.getTaskRqcId());
			Restriction and = Restrictions.and(eq, eq2);
			criteria.setRestriction(and);
			RqcLines rqcLines = new RqcLines();
			BeanUtils.copyProperties(rqcLinesDTO, rqcLines);
			this.buildField(rqcLines, true, userDTO, now);
			rqcHeaderId = rqcLinesDTO.getRqcHeaderId();
			rqcLines.setTimes(2); // 次数2
			this.mapper.updateFieldsByCriteria(rqcLines, fs, criteria);
            List<RqcLines> byCriteria = this.mapper.findByCriteria(criteria);
            if(byCriteria.size()>0){
                qcOpcode1 = byCriteria.get(0).getQcOpcode1();
            }
            qcOpcode2 = rqcLines.getQcOpcode2();
		}
		if(!StringUtils.isEmpty(qcOpcode2)){
			// 更新头表 TODO 质检人1,质检人2
			rqcHeadersMapper.updateMapById(rqcHeaderId,MapUtils.put("qcOperator1",qcOpcode1).put("qcOperator2",qcOpcode2).getMap(), RqcHeaders.class);
		}

	}

	/**
	 * 根据质检行明细结论分组推送任务
	 * 
	 * @param list
	 * 
	 * @param rqcLinesDTOList
	 * @param list3
	 */
	private void excutePushTaskPool(List<RqcLines> list, List<RqcLinesDTO> list3, List<RqcLinesDTO> rqcLinesDTOList,
			boolean isAuto) {
		if (ObjectUtils.isNull(rqcLinesDTOList))
			return;

		// 构建向下流转的关联id
		try {
			excuteBuildRelatedId(list, rqcLinesDTOList, list3);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// 根据质检的结论分组到复检组,上架组,拒收组 TODO
		// 判断此质检是第几次
		// 根据结论退不同的任务池,可考虑是否异步
		// 1. 结论分组
		Map<String, List<RqcLinesDTO>> collect = Optional.ofNullable(rqcLinesDTOList).orElse(Collections.emptyList())
				.stream().distinct().collect(Collectors.groupingBy(p -> {
					RqcLinesDTO dto = (RqcLinesDTO) p;
					String conclusion = "";
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = dto.getQcResult3();
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = dto.getQcResult2();
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = dto.getQcResult1();
					conclusion = dto.getStockStatus();
					if (ObjectUtils.isNull(conclusion))
						conclusion = "0"; // 为空默认合格
					return conclusion;
				}));
		AssertUtils.notNull(collect, "质检行数据根据结论分组为空!");
		// 2. 找寻策略(收货头表id)
		String rcvHeaderId = rqcLinesDTOList.get(0).getRcvHeaderId();
		RcvTypeStrategyEnum rcvTypeStrategyEnum = taskHelper.getRcvTypeStrategyEnum(rcvHeaderId);
		RqcStrategyEnum rqcStrategyEnum = taskHelper.getRqcStrategyEnum(rcvHeaderId);

		// 收集需要质检返回后的数据(打印用)
		for (List<RqcLinesDTO> rqcLinesList : collect.values()) {
			String conclusion = "";
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = rqcLinesList.get(0).getQcResult3();
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = rqcLinesList.get(0).getQcResult2();
//					if (ObjectUtils.isNull(conclusion))
//						conclusion = rqcLinesList.get(0).getQcResult1();
			conclusion = rqcLinesList.get(0).getStockStatus();

			// 3. 双人质检过滤
			// 双人质检 次数为0 只是保存,不走任务池
			Integer itemHealthIsDouble = rqcLinesList.get(0).getItemHealthIsDouble();
			Integer times = rqcLinesList.get(0).getTimes();
			String rcvType = rqcLinesList.get(0).getRcvType();
			if (itemHealthIsDouble == null)
				itemHealthIsDouble = 0;
			// 结论控制 只有结论为0(合格)的且双人质检才会判断处理不处理任务
			// 自动单据自动双人质检直接往下流转
			if (isAuto) {
				excutePushTask(rqcLinesList, conclusion, rcvTypeStrategyEnum, rqcStrategyEnum, isAuto);
				if ((rcvType.equals(BizConstant.PURCHASE_IN) || rcvType.equals(BizConstant.SALE_RETURN_IN))
						&& (conclusion.equals(BizConstant.QUALIFIED) || conclusion.equals(BizConstant.UN_QUALIFIED))) {
				}
			} else {
				if (1 == itemHealthIsDouble && conclusion.equals("0")) {
					if (2 == times) {
						// 第二次质检
						// 4. 推送任务
						excutePushTask(rqcLinesList, conclusion, rcvTypeStrategyEnum, rqcStrategyEnum, isAuto);
						if ((rcvType.equals(BizConstant.PURCHASE_IN) || rcvType.equals(BizConstant.SALE_RETURN_IN))
								&& (conclusion.equals(BizConstant.QUALIFIED)
										|| conclusion.equals(BizConstant.UN_QUALIFIED))) {
						}
					}

				} else {
					// 不是双人且不是合格结论 放行
					// 4. 推送任务
					excutePushTask(rqcLinesList, conclusion, rcvTypeStrategyEnum, rqcStrategyEnum, isAuto);
					if ((rcvType.equals(BizConstant.PURCHASE_IN) || rcvType.equals(BizConstant.SALE_RETURN_IN))
							&& (conclusion.equals(BizConstant.QUALIFIED)
									|| conclusion.equals(BizConstant.UN_QUALIFIED))) {
					}
				}
			}

		}

	}

	private void excuteBuildRelatedId(List<RqcLines> list, List<RqcLinesDTO> rqcLinesDTOList, List<RqcLinesDTO> list3) {
		Map<String, List<RqcLinesDTO>> collect2 = rqcLinesDTOList.stream()
				.collect(Collectors.groupingBy(RqcLinesDTO::getTaskRqcId));
		if (ObjectUtils.isNotNull(collect2)) {
			// 新增的id
			if (ObjectUtils.isNotNull(list)) {
				for (RqcLines line : list) {
					String taskRqcId = line.getTaskRqcId();
					List<RqcLinesDTO> list2 = collect2.get(taskRqcId);
					if (ObjectUtils.isNotNull(list2)) {
						list2.get(0).setRqcLineId(line.getRqcLineId());
					}
				}
			}
			// 修改的id
			if (ObjectUtils.isNotNull(list3)) {
				Set<String> collect = list3.stream().map(RqcLinesDTO::getTaskRqcId).collect(Collectors.toSet());
				String[] array = collect.toArray(new String[collect.size()]);
				Criteria crt = Criteria.forClass(RqcLines.class);
				crt.setRestriction(Restrictions.in("taskRqcId", array));
				String[] includes = { "rqcLineId", "taskRqcId" };
				FieldSelector include = FieldSelector.newInstance().include(includes);
				List<RqcLines> findFieldsByCriteria = this.mapper.findFieldsByCriteria(include, crt);
				if (findFieldsByCriteria != null) {
					for (RqcLines rqcLines : findFieldsByCriteria) {
						String taskRqcId = rqcLines.getTaskRqcId();
						List<RqcLinesDTO> list2 = collect2.get(taskRqcId);
						if (ObjectUtils.isNotNull(list2)) {
							list2.get(0).setRqcLineId(rqcLines.getRqcLineId());
						}
					}
				}
			}
		}

	}

	/**
	 * 质检行明细批量保存
	 * 
	 * @param list
	 */
	private void excuteBatchSave(List<RqcLines> list) {
		if (ObjectUtils.isNull(list))
			return;

		// 保存质检行
		if (list.size() > 500) {
			try {
				DaoUtils.saveBatch(this.mapper, list, 500);
			} catch (Exception e) {
				logger.error("质检行保存失败,错误详情:", e);
				throw new BizException("批量保存质检行失败!");
			}
		} else {
			this.mapper.saveBatch(list);
		}
	}

	/**
	 * 双人质检逻辑处理
	 * 
	 * @param rqcLinesDTO
	 * @param taskIds
	 * @param now
	 * @return
	 */
	private Integer excuteDoubleVaildate(RqcLinesDTO rqcLinesDTO, List<String> taskIds, Date now, int row) {
		rqcLinesDTO.setQcStatus3("1");
		rqcLinesDTO.setQcStatus2("1");
		rqcLinesDTO.setQcStatus1("1");
		// 双人质检判断
		Integer itemHealthIsDouble = rqcLinesDTO.getItemHealthIsDouble();
		String taskRqcId = rqcLinesDTO.getTaskRqcId();
		// 获取任务池中任务质检次数
		TaskQcDetailDTO taskQcDetailDTO = taskQcDetailService.findByPkId(taskRqcId);

		AssertUtils.notNull(taskQcDetailDTO, String.format("第[%d]行,质检任务id:[%s]查询的任务为空!", row, taskRqcId));
		// 一个Task对应一个行
		String status = taskQcDetailDTO.getStatus();
		if (!"1".equals(status))
			throw new BizException(String.format("第[%d]行,质检任务id:[%s]查询的任务已经执行完毕,请刷新重试!", row, taskRqcId));
		Integer dataVersion = taskQcDetailDTO.getDataVersion();

		// 加锁 使用数据库乐观锁
		// 根据数据库data_version 字段来加锁
		Criteria criteria = new Criteria(TaskQcDetail.class);
		criteria.setRestriction(Restrictions.and(Restrictions.eq("taskRqcId", taskRqcId),
				Restrictions.eq("dataVersion", dataVersion), Restrictions.eq("status", status)));
		long count = taskQcDetailMapper.updateMapByCriteria(
				MapUtils.put("dataVersion", dataVersion + 1).put("executor", userUtils.getUserName()).getMap(),
				criteria);
		if (0 >= count)
			throw new BizException(String.format("第%d行[任务id:%s]数据正在进行处理,请刷新重试!", row, taskRqcId));

		Integer times = taskQcDetailDTO.getTimes();
		if (1 == itemHealthIsDouble) {
			// 为双人质检
			// 如果次数为0 放行 次数加1
			if (0 == times) {
				// 更新任务池中质检次数
//				updateTaskPoolTime(taskRqcId, times);
				// 质检1永远为最新字段
				// 保存质检2的信息
				// 前端永远根据质检2来保存
				Date qcDate1 = rqcLinesDTO.getQcDate1();
				String qcOpcode1 = rqcLinesDTO.getQcOpcode1();
				if (ObjectUtils.isNull(qcDate1))
					rqcLinesDTO.setQcDate2(now);
				if (ObjectUtils.isNull(qcOpcode1))
					rqcLinesDTO.setQcOpcode2(userUtils.getUserName());
				rqcLinesDTO.setQcReason2(rqcLinesDTO.getQcReason1());
				rqcLinesDTO.setQcResult2(rqcLinesDTO.getQcResult1());
			}
			if (1 == times) {
//				updateTaskPoolTime(taskRqcId, times);
				taskIds.add(taskRqcId);
				// 保存质检2的信息
				Date qcDate1 = rqcLinesDTO.getQcDate1();
				String qcOpcode1 = rqcLinesDTO.getQcOpcode1();
				if (ObjectUtils.isNull(qcDate1))
					rqcLinesDTO.setQcDate1(now);
				if (ObjectUtils.isNull(qcOpcode1))
					rqcLinesDTO.setQcOpcode1(userUtils.getUserName());

				rqcLinesDTO.setStockStatus(rqcLinesDTO.getQcResult1());
			}
			if (2 == times) {
				throw new BizException(String.format("批量保存质检行失败!taskRqcId为[%s]的任务已处理", taskRqcId));
			}

		} else {
			// 不是双人 放行
			Date qcDate1 = rqcLinesDTO.getQcDate1();
			String qcOpcode1 = rqcLinesDTO.getQcOpcode1();
			if (ObjectUtils.isNull(qcDate1))
				rqcLinesDTO.setQcDate1(now);
			if (ObjectUtils.isNull(qcOpcode1))
				rqcLinesDTO.setQcOpcode1(userUtils.getUserName());

//			updateTaskPoolTime(taskRqcId, times);
			taskIds.add(taskRqcId);
		}
		// (作废)前端根据大于1来判断

		return times;
	}

	/**
	 * 调用具体策略来向下推送任务
	 * 
	 * @param rqcLinesList
	 * @param conclusion
	 * @param rcvTypeStrategyEnum
	 * @param rqcStrategyEnum
	 * @param isAuto
	 */
	private void excutePushTask(List<RqcLinesDTO> rqcLinesList, String conclusion,
			RcvTypeStrategyEnum rcvTypeStrategyEnum, RqcStrategyEnum rqcStrategyEnum, boolean isAuto) {
		if (ObjectUtils.isNull(rqcLinesList))
			return;
		// 推送任务
		if (ObjectUtils.isNull(conclusion))
			conclusion = "0";
		// 调用策略工厂来组织执行器执行任务
		RcvSubjectFactory factory = new RcvSubjectFactoryS1Impl();
		Map<String, Object> map = new HashedMap<>();
		map.put("data", rqcLinesList);
		// map 放入 mtlOwnerId、warehouseId
		map.put("mtlOwnerId", rqcLinesList.get(0).getMtlOwnerId());
		map.put("warehouseId", rqcLinesList.get(0).getWarehouseId());
		ConclusionEnum conclusionEnum = taskHelper.getConclusionEnum(conclusion);
		factory.excuteTask(map, handler, rcvTypeStrategyEnum, rqcStrategyEnum, conclusionEnum, isAuto);

		// 推送任务时需要加上推荐库别,推荐库位 TODO
	}

	/**
	 * 更新质检任务池任务次数(乐观锁)
	 * 
	 * @param taskRqcId
	 * @param times
	 */
//	private void updateTaskPoolTime(String taskRqcId, Integer times) {
//		Criteria criteria = new Criteria(TaskQcDetail.class);
//		criteria.setRestriction(
//				Restrictions.and(Restrictions.eq("taskRqcId", taskRqcId), Restrictions.eq("times", times)));
//		// 乐观锁
//		long l = taskQcDetailMapper.updateMapByCriteria(MapUtils.put("times", times + 1).getMap(), criteria);
//		if (l == 0L) {
//			throw new BizException(String.format("批量保存质检行失败!taskRqcId为[%s]的任务正在处理", taskRqcId));
//		}
//	}

	/**
	 * 更新质检任务池状态(0不可用1可用)
	 * 
	 * @param taskIds
	 */
	private void updateTaskPoolStatus(List<String> taskIds) {
		if (ObjectUtils.isNull(taskIds))
			return;
		// 更新质检池任务状态 为已执行
		Criteria criteria = new Criteria(TaskQcDetail.class);
		criteria.setRestriction(Restrictions.in("taskRqcId", taskIds.toArray()));

		// 20220408新加
		List<TaskQcDetail> findByCriteria = taskQcDetailMapper.findByCriteria(criteria);
		for (TaskQcDetail taskQcDetail : findByCriteria) {
			Integer dataVersion = taskQcDetail.getDataVersion();
			String taskRqcId = taskQcDetail.getTaskRqcId();
			String status = taskQcDetail.getStatus();
			if (!status.equals("1")) {
				throw new BizException(String.format("验收任务id[%s],任务状态为已完成,请重试!", taskRqcId));
			}
			long count = taskQcDetailMapper.updateMapById(taskRqcId, MapUtils.put("status", "0")
					.put("executor", userUtils.getUserName()).put("dataVersion", dataVersion + 1).getMap(),
					TaskQcDetail.class);
			if (0 >= count)
				throw new BizException(String.format("任务id:[%s]数据正在进行处理,请刷新重试!", taskRqcId));
		}
		// 20220408新加

//		taskQcDetailMapper.updateMapByCriteria(
//				MapUtils.put("status", "0").put("executor", userUtils.getUserName()).getMap(), criteria); // 置为已完成

//		taskQcDetailMapper.updateMapByCriteria(MapUtils.put("status", "0").put("isLock", 0).getMap(), criteria); // 置为已完成
	}

//	private boolean canCommit(RqcLinesDTO rqcLinesDTO) {
//		// 校验任务是否已被处理了
//		String taskRqcId = rqcLinesDTO.getTaskRqcId();
//		// 一个Task对应一个行
//		Criteria criteria = new Criteria(RqcLines.class);
//		criteria.setRestriction(Restrictions.eq("taskRqcId", taskRqcId));
//		long l = this.mapper.findCountByCriteria(criteria);
//		if (l > 0)
//			return false;
//		return true;
//	}

	private void buildField(RqcLines lines, boolean editFlag, UserDTO userDTO, Date now) {
		// 构建系统基础字段
		this.setBaseSysField(lines, editFlag, userDTO, now);
		vaildateModelRepeated(lines, editFlag, userDTO);
	}

	private void buildDefaultField(RqcLinesDTO rqcLinesDTO, boolean editFlag, UserDTO userDTO) {
		// 构建默认字段
		String qcStatus1 = rqcLinesDTO.getQcStatus1();
		String qcStatus2 = rqcLinesDTO.getQcStatus2();
		String qcStatus3 = rqcLinesDTO.getQcStatus3();
		Integer times = rqcLinesDTO.getTimes();
		if (!editFlag && ObjectUtils.isNull(qcStatus1))
			rqcLinesDTO.setQcStatus1("1");

		if (!editFlag && ObjectUtils.isNull(qcStatus2))
			rqcLinesDTO.setQcStatus2("0");

		if (!editFlag && ObjectUtils.isNull(qcStatus3))
			rqcLinesDTO.setQcStatus3("0");

		if (!editFlag && ObjectUtils.isNull(times))
			rqcLinesDTO.setTimes(1);

		String qcOpcode1 = rqcLinesDTO.getQcOpcode1();
		Date qcDate1 = rqcLinesDTO.getQcDate1();
		String qcReason1 = rqcLinesDTO.getQcReason1();
		String qcResult1 = rqcLinesDTO.getQcResult1();
		if (!editFlag && qcDate1 == null) {
			rqcLinesDTO.setQcDate1(new Date());
		}
		if (!editFlag && StringUtils.isBlank(qcOpcode1)) {
			rqcLinesDTO.setQcOpcode1(userDTO.getUsername());
		}
		if (!editFlag && StringUtils.isBlank(qcReason1)) {
			rqcLinesDTO.setQcReason1(rqcLinesDTO.getHandlingReason());
		}
		if (!editFlag && StringUtils.isBlank(qcResult1)) {
			rqcLinesDTO.setQcResult1(rqcLinesDTO.getStockStatus());
		}
	}

	@Override
	public Page<RqcLinesDTO> findList(RqcLinesDTO rqcLinesDTO, PageParam pageParam) {

		Criteria criteria = buildPageParam(pageParam, true, null, RqcLines.class);
		Restriction r = buildCondition(rqcLinesDTO);
		criteria.setRestriction(r);
		this.startPage(pageParam);
		List<RqcLines> list = this.mapper.findByCriteria(criteria);
		Page<RqcLines> page = PageUtils.getPage(list);
		Page<RqcLinesDTO> page2 = this.buildPage(page, (p) -> {
			RqcLinesDTO target = new RqcLinesDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		});
		return page2;
	}

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

		String rcvHeaderId = rqcLinesDTO.getRcvHeaderId();
		String asnHeaderId = rqcLinesDTO.getAsnHeaderId();
		String itemId = rqcLinesDTO.getItemId();
		String stockStatus = rqcLinesDTO.getStockStatus();
		String rqcHeaderId = rqcLinesDTO.getRqcHeaderId();

		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(rqcHeaderId) ? null : Restrictions.eq("rqcHeaderId", rqcHeaderId);
		Restriction r5 = StringUtils.isBlank(stockStatus) ? null : Restrictions.eq("stockStatus", stockStatus);

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

//	private void excuteSaveOthers(RqcLinesDTO rqcLinesDTO, RqcLines lines, UserDTO userDTO, Date now) {
//	// 添加其他关联数据
//	List<RqcLinePicDTO> rqcLinePicDTOList = rqcLinesDTO.getRqcLinePicDTOList();
//	if (ObjectUtils.isNotNull(rqcLinePicDTOList)) {
//		// 操作质检后图片
//		String rqcLineId = lines.getRqcLineId();
//		rqcLinePicService.batchAdd(rqcLinePicDTOList, rqcLineId, userDTO, now);
//	}
//
//}
	@Override
	public Object add(RqcLinesDTO rqcLinesDTO) {
		// TODO vaildate
		UserDTO userDTO = userUtils.getUserDTO();
		RqcLines rqcLines = new RqcLines();
		BeanUtils.copyProperties(rqcLinesDTO, rqcLines);
		this.vaildateModel(rqcLines, false, userDTO);
		this.buildField(rqcLines, false, userDTO);
		this.mapper.save(rqcLines);
		return "";
	}

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

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

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

	@Override
	@Transactional
	public Object batchAdd(List<RqcLinesDTO> rqcLinesDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		for (RqcLinesDTO rqcLinesDTO : rqcLinesDTOList) {
			RqcLines rqcLines = new RqcLines();
			BeanUtils.copyProperties(rqcLinesDTO, rqcLines);
			this.vaildateModel(rqcLines, false, userDTO);
			this.buildField(rqcLines, false, userDTO);
			this.mapper.save(rqcLines);
		}
		return "";
	}

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

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

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

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

	private void buildField(RqcLines rqcLines, Boolean editFlag, UserDTO userDTO) {

		this.buildField(rqcLines, editFlag, userDTO, new Date());
	}

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

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

	@Override
	public Page<RqcLinesDTO> findList(RqcDQueryVO queryVO) {
		queryVO.setEnterpriseId(userUtils.getEnterpriseId());
		this.startPage(queryVO);
		List<RqcLinesDTO> list = this.mapper.findList(queryVO);
		return PageUtils.getPage(list);
	}

	@Override
	public RqcLinesDTO findByPkId(String pkId) {
		// TODO
		AssertUtils.isNotBlank(pkId, "查询的主键id不可为空!");
		RqcLinesDTO rqcLinesDTO = this.mapper.findByPkId(pkId);
		AssertUtils.notNull(rqcLinesDTO, "查询对象为空!");
		return rqcLinesDTO;
	}

	@Override
	@Transactional
	public Object batchAdd(List<RqcLinesDTO> rqcLinesDTOList, String masterId, UserDTO userDTO, Date now) {
		this.batchAdd(rqcLinesDTOList, masterId, userDTO, now, 0, "", true, false, false);
		return true;
	}

	private void excuteExpirDate(List<RqcLinesDTO> list3, Date now) {
		for (RqcLinesDTO rqcLinesDTO : list3) {
			String rcvType = rqcLinesDTO.getRcvType();
			Date batchExpiredDate = rqcLinesDTO.getBatchExpiredDate();
			if (null == batchExpiredDate)
				return;

			Long subtract = DateUtils.subtract(now, batchExpiredDate, ChronoUnit.DAYS);
			// 退货入库效期处理
//			if (!StringUtils.isBlank(rcvType) && rcvType.equals(2) && subtract <= 0) {
//				// 过期处理
//				if (enableExpire) {
//					rqcLinesDTO.setStockStatus("1"); // 结论不合格
//					rqcLinesDTO.setQcResult1("1"); // 结论不合格
//				}
//			}
			// 其他类型的入库效期处理 TODO

		}
	}

	private void excuteInsert(List<String> taskIds, List<RqcLines> list, List<RqcLinesDTO> list3,
			RqcLinesDTO rqcLinesDTO, boolean editFlag, UserDTO userDTO, int row, Date now, String taskRqcId,
			Integer times) {
		taskIds.add(taskRqcId);
		rqcLinesDTO.setTimes(times + 1);
		rqcLinesDTO.setRqcDate(now);
		this.buildDefaultField(rqcLinesDTO, editFlag, userDTO);
		this.vaildateModel(rqcLinesDTO, editFlag, userDTO, row, validator,
				SERVICE_MSG + OperationConstant.BATCH_ADD_OPERATION);
		RqcLines lines = new RqcLines();
		BeanUtils.copyProperties(rqcLinesDTO, lines);
		this.buildField(lines, editFlag, userDTO, now);
		lines.setQcDate1(now);
		list.add(lines);
		list3.add(rqcLinesDTO);
	}

	private Integer getTaskTimes(RqcLinesDTO rqcLinesDTO, Date now, int row) {
		// 双人质检判断
		String taskRqcId = rqcLinesDTO.getTaskRqcId();
		// 获取任务池中任务质检次数
		TaskQcDetailDTO taskQcDetailDTO = taskQcDetailService.findByPkId(taskRqcId);

		AssertUtils.notNull(taskQcDetailDTO, String.format("第[%d]行,质检任务id:[%s]查询的任务为空!", row, taskRqcId));
		// 一个Task对应一个行
		String status = taskQcDetailDTO.getStatus();
		if (!"1".equals(status))
			throw new BizException(String.format("第[%d]行,质检任务id:[%s]查询的任务已经执行完毕,请刷新重试!", row, taskRqcId));
		// 在这里枷锁
		Integer dataVersion = taskQcDetailDTO.getDataVersion();

		// 加锁 使用数据库乐观锁
		// 根据数据库data_version 字段来加锁
		Criteria criteria = new Criteria(TaskQcDetail.class);
		criteria.setRestriction(Restrictions.and(Restrictions.eq("taskRqcId", taskRqcId),
				Restrictions.eq("dataVersion", dataVersion), Restrictions.eq("status", status)));
		long count = taskQcDetailMapper.updateMapByCriteria(
				MapUtils.put("dataVersion", dataVersion + 1).put("executor", userUtils.getUserName()).getMap(),
				criteria);
		if (0 >= count)
			throw new BizException(String.format("第%d行[任务id:%s]数据正在进行处理,请刷新重试!", row, taskRqcId));

		rqcLinesDTO.setPieceQty(taskQcDetailDTO.getPieceQty()); // 数量取验收任务中的数量,免得前端抛错

		String whAreaCategoryCode = taskQcDetailDTO.getWhAreaCategoryCode();
		String whAreaCategory = rqcLinesDTO.getWhAreaCategory();
		String whAreaCategoryCode2 = rqcLinesDTO.getWhAreaCategoryCode();
		if (StringUtils.isBlank(whAreaCategory)) {
			rqcLinesDTO.setWhAreaCategory(whAreaCategoryCode);
		}
		if (StringUtils.isBlank(whAreaCategoryCode2)) {
			rqcLinesDTO.setWhAreaCategoryCode(rqcLinesDTO.getWhAreaCategory());
		}
		Integer refType = taskQcDetailDTO.getRefType();
		String refLineId = taskQcDetailDTO.getRefLineId();
		rqcLinesDTO.setRefType(refType);
		rqcLinesDTO.setRefLineId(refLineId);

		return taskQcDetailDTO.getTimes();
	}
//	@Override
//	@Transactional
//	public Object batchAdd(List<RqcLinesDTO> rqcLinesDTOList, String masterId, UserDTO userDTO, Date now) {
//		// 批量添加
//		if (ObjectUtils.isNull(userDTO))
//			userDTO = userUtils.getUserDTO();
//		if (ObjectUtils.isNull(now))
//			now = new Date();
//		int row = 0;
//		boolean editFlag = Boolean.FALSE;
//		// 需要保存的rqc
//		List<RqcLines> list = new ArrayList<>();
//		List<String> taskIds = new ArrayList<>();
//		List<String> taskIds2 = new ArrayList<>();
//		// 需要更新的rqc
//		List<RqcLinesDTO> list2 = new ArrayList<>();
//		for (RqcLinesDTO rqcLinesDTO : rqcLinesDTOList) {
//			row++;
//			String taskRqcId = rqcLinesDTO.getTaskRqcId();
//			taskIds2.add(taskRqcId);
//			// 1. 执行双人质检逻辑 (这里可能需要优化)
//			Integer times = excuteDoubleVaildate(rqcLinesDTO, taskIds, now, row);
//			
//			String rqcHeaderId = rqcLinesDTO.getRqcHeaderId();
//			// 判断质检的次数
//			// 等于0
//			if (0 == times) {
//				Integer itemHealthIsDouble = rqcLinesDTO.getItemHealthIsDouble();
//				// 判断是否双人质检
//				if (0 == itemHealthIsDouble) {
//					rqcLinesDTO.setTimes(times + 1);
//					list2.add(rqcLinesDTO);
//				}
//				// 头表id
//				if (ObjectUtils.isNull(rqcHeaderId))
//					rqcLinesDTO.setRqcHeaderId(masterId);
//				this.buildDefaultField(rqcLinesDTO, editFlag, userDTO);
//				this.vaildateModel(rqcLinesDTO, editFlag, userDTO, row, validator,
//						SERVICE_MSG + OperationConstant.BATCH_ADD_OPERATION);
//				RqcLines lines = new RqcLines();
//				BeanUtils.copyProperties(rqcLinesDTO, lines);
//				this.buildField(lines, editFlag, userDTO, now);
//				lines.setTimes(times + 1); // 次数加1
//				list.add(lines);
//			}
//			// 等于1
//			if (1 == times) {
//				// 头表id
//				// 更新信息 双人质检以及操作过
//				rqcLinesDTO.setTimes(times + 1);
//				list2.add(rqcLinesDTO);
//			}
//			// 等于2
//			if (2 >= times)
//				continue;
////			
////			this.mapper.save(lines);
////			excuteSaveOthers(rqcLinesDTO, lines, userDTO, now);
//		}
//		// 2. 保存质检行
//		excuteBatchSave(list);
//		
//		// 2.1 更新二次质检数据
//		excuteBatchUpdate(list2, userDTO);
//		
//		// 3. 更新质检任务池状态(需要根据双人质检来)
//		this.updateTaskPoolStatus(taskIds);
//		
//		// 3.1 更新质检执行者
//		this.updateTaskPoolExcuter(taskIds2);
//		
//		// 4. 保存任务池
//		this.excutePushTaskPool(list2);
//		
//		return true;
//	}

	@Override
	@Transactional
	@TxTransaction(isStart = true)
	public Object batchAdd(List<RqcLinesDTO> rqcLinesDTOList, RqcHeadersDTO rqcHeadersDTO, UserDTO userDTO, Date now,
			boolean isPad) {
		String masterId = rqcHeadersDTO.getRqcHeaderId();
		Integer isInstockPrint = rqcHeadersDTO.getIsInstockPrint();
		String autoBillNum = rqcHeadersDTO.getAutoBillNum();
		return this.batchAdd(rqcLinesDTOList, masterId, userDTO, now, isInstockPrint, autoBillNum, true, false, isPad);
	}

	/**
	 * 质检明细保存逻辑
	 * 
	 * @param rqcLinesDTOList
	 * @param masterId
	 * @param userDTO
	 * @param now
	 * @param isInstockPrint
	 * @param autoBillNum
	 * @param enableValidateRqcReportNo 是否校验自动单号
	 * @param isAuto                    是否自动生成
	 * @return
	 */
	private Object batchAdd(List<RqcLinesDTO> rqcLinesDTOList, String masterId, UserDTO userDTO, Date now,
			Integer isInstockPrint, String autoBillNum, boolean enableValidateRqcReportNo, boolean isAuto,
			boolean isPad) {
		// 批量添加
		if (ObjectUtils.isNull(userDTO))
			userDTO = userUtils.getUserDTO();
		if (ObjectUtils.isNull(now))
			now = new Date();
		int row = 0;
		boolean editFlag = Boolean.FALSE;
		// 需要保存的rqc
		List<RqcLines> list = new ArrayList<>();
		// 更新任务状态
		List<String> taskIds = new ArrayList<>();
		// 更新任务执行者
		List<String> taskIds2 = new ArrayList<>();
		// 需要更新的rqc
		List<RqcLinesDTO> list2 = new ArrayList<>();
		// 需要往下推送任务的
		List<RqcLinesDTO> list3 = new ArrayList<>();
		// 双人第一次质检的集合
		List<String> taskIds3 = new ArrayList<>();
		RqcLinesDTO rqcLinesDTO3 = rqcLinesDTOList.get(0);

		Set<String> zjContainerCode = new HashSet<>();
		Set<String> sjContainerCode = new HashSet<>();
		String warehouseId = rqcLinesDTO3.getWarehouseId();
		String mtlOwnerId = rqcLinesDTO3.getMtlOwnerId();
		String businessControlValue = taskHelper.getBusinessControlValue(warehouseId, mtlOwnerId, "1",
				BizConstant.ENABLE_VAILDATE_CONTAINER);

		Map<String, List<RqcLinesDTO>> collect = rqcLinesDTOList.stream()
				.filter(p -> !StringUtils.isBlank(p.getRqcReportNo()))
				.collect(Collectors.groupingBy(RqcLinesDTO::getBatchId));
		ValidList<InvStockBatchNumberUpdate> batchNumbers = new ValidList<>();
		if (!ObjectUtils.isNull(collect)) {
			Criteria crt = Criteria.forClass(RcvLines.class);
			for (List<RqcLinesDTO> rqcLineList : collect.values()) {
				if (!ObjectUtils.isNull(rqcLineList)) {
					int size = rqcLineList.size();
					RqcLinesDTO rqcLinesDTO = rqcLineList.get(0);
					String manufacturerLotNum = rqcLinesDTO.getManufacturerLotNum();
					String rqcReportNo = rqcLinesDTO.getRqcReportNo();
					String batchId = rqcLinesDTO.getBatchId();

					if (enableValidateRqcReportNo) {
						if (size >= 2) {
							for (int i = 1; i < size; i++) {
								RqcLinesDTO rqcLinesDTO2 = rqcLineList.get(i);
								String rqcReportNo2 = rqcLinesDTO2.getRqcReportNo();
								if (!rqcReportNo2.equals(rqcReportNo)) {
									throw new BizException(
											String.format("相同批号[%s]对应的质检报告编号不一致,请检查后重试!", manufacturerLotNum));
								}
							}
						}
					}

					// 更新收货行信息
					crt.setRestriction(Restrictions.eq("batchId", batchId));
					rcvLinesMapper.updateMapByCriteria(
							MapUtils.put("rqcReportNo", rqcReportNo).put("gmtModified", now).getMap(), crt);

					// 更新批次信息
					InvStockBatchNumberUpdate ibnu = new InvStockBatchNumberUpdate();
					ibnu.setBatchId(batchId);
					ibnu.setRqcReportNo(rqcReportNo);
					batchNumbers.add(ibnu);
				}
			}
		}
		if (!ObjectUtils.isNull(batchNumbers)) {
			RestMessage updateBatchNumber = null;
			String errorMsg = "质检更新批次质检报告单号操作,调用远程库存服务调整批次信息失败!";
			try {
				updateBatchNumber = baseInventoryRemoteCaller.updateBatchNumber(batchNumbers);
			} catch (Exception e) {
				logger.error(errorMsg + "原因->{}", e);
				throw new BizException(errorMsg);
			}
			if (updateBatchNumber == null) {
				throw new BizException(errorMsg);
			}
			if (!updateBatchNumber.isSuccess()) {
				if (updateBatchNumber.getData() != null) {
					throw new BizException(errorMsg + "原因->" + updateBatchNumber.getMessage()
							+ updateBatchNumber.getData().toString());
				} else {
					throw new BizException(errorMsg + "原因->" + updateBatchNumber.getMessage());
				}

			}
		}

		Map iqueryMap = new HashMap<>();
		List<Map> iqList = new ArrayList<>();
		Map<String, String> cc = new HashMap<>();

		List<RcvCommonLine> clList = new ArrayList<>();


		//需要占用的容器集合
		List<String> newContainerCodeList = new ArrayList<>();
		//需要释放的容器集合
		List<String> oldContainerCodeList = new ArrayList<>();

		for (RqcLinesDTO rqcLinesDTO : rqcLinesDTOList) {
			row++;

			//校验是否更换容器
			if(!rqcLinesDTO.getContainerCode().equals(rqcLinesDTO.getOldContainerCode())){
				newContainerCodeList.add(rqcLinesDTO.getContainerCode());
				//查询源容器是否还有质检任务
				Criteria crt = Criteria.forClass(TaskQcDetail.class);
				crt.restrictionBuilder().eq("containerCode",rqcLinesDTO.getOldContainerCode())
						.eq("status","1").notIn("taskRqcId",new String[]{rqcLinesDTO.getTaskRqcId()});
				crt.buildRestriction();
				List<TaskQcDetail> byMap = taskQcDetailMapper.findByCriteria(crt);
				if(byMap.size() == 0){
					oldContainerCodeList.add(rqcLinesDTO.getOldContainerCode());
				}
			}
			// 增加商品校验
			Map qmap = new HashMap<>();
			qmap.put("itemId", rqcLinesDTO.getItemId());
			qmap.put("itemCategoryCode", rqcLinesDTO.getCategoryId());
			qmap.put("refId", row);
			qmap.put("flag", false);
			qmap.put("message", "");
			iqList.add(qmap);

			//温度校验
			if(!StringUtils.isEmpty(rqcLinesDTO.getStoreTemperature())
					&&(rqcLinesDTO.getStoreTemperature().equals("恒温")
					||rqcLinesDTO.getStoreTemperature().equals("冷冻")
					||rqcLinesDTO.getStoreTemperature().equals("冷藏"))){
				if(StringUtils.isEmpty(rqcLinesDTO.getRqcTemperature())){
					throw new BizException(String.format("第[%d]行存储条件为恒温，冷冻，冷藏，验收温度不能为空",row));
				}
			}

			// 获取质检的次数
			Integer times = getTaskTimes(rqcLinesDTO, now, row);

			rqcLinesDTO.setRqcHeaderNo(autoBillNum);
			// 数据准确性计算
			BigDecimal pieceQty = rqcLinesDTO.getPieceQty();
			BigDecimal conversionRate = rqcLinesDTO.getConversionRate();
			if (conversionRate == null) {
				conversionRate = BigDecimal.ONE;
				rqcLinesDTO.setConversionRate(conversionRate);
			}
			if (pieceQty == null) {
				pieceQty = BigDecimal.ZERO;
				rqcLinesDTO.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); // 包装总量
			// 保证数据正确性再次进行计算
			rqcLinesDTO.setOddCaseQty(caseQty);
			rqcLinesDTO.setOddPieceQty(oddPieceQty);

			String taskRqcId = rqcLinesDTO.getTaskRqcId();
			taskIds2.add(taskRqcId);

			Integer isInstockPrint2 = rqcLinesDTO.getIsInstockPrint();
//			String rqcHeaderId = rqcLinesDTO.getRqcHeaderId();
//			if (ObjectUtils.isNull(rqcHeaderId))
			rqcLinesDTO.setRqcHeaderId(masterId);
			// 记录是否打印标识
			if (ObjectUtils.isNull(isInstockPrint2))
				rqcLinesDTO.setIsInstockPrint(isInstockPrint);

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

			if (!StringUtils.isBlank(businessControlValue) && businessControlValue.equals("1")) {
				// 商品大类
				Map<String, String> categoryIdMap = new HashMap<>();
				// 存储分类
				Map<String, String> itemHealthStoreCategoryMap = new HashMap<>();
				// 存储条件
				Map<String, String> itemStoreTempMap = new HashMap<>();
				String containerCode = rqcLinesDTO.getContainerCode();
				String categoryId = rqcLinesDTO.getCategoryId();
				String itemHealthStoreCategory = rqcLinesDTO.getItemHealthStoreCategory();
				String storeTemperature = rqcLinesDTO.getStoreTemperature();
				if (!StringUtils.isBlank(containerCode) && !"N/A".equals(containerCode)) {
					String itemLot1 = categoryIdMap.get(containerCode);
					String itemLot4 = itemHealthStoreCategoryMap.get(containerCode);
					String itemLot6 = itemStoreTempMap.get(containerCode);
					if (StringUtils.isBlank(itemLot1)) {
						categoryIdMap.put(containerCode, categoryId);
					} else {
						if (!itemLot1.equals(categoryId)) {
							throw new BizException(
									String.format("商品大类不同不可选同容器,容器[%s],商品[%s]", containerCode, rqcLinesDTO.getItemName()));
						}
					}
					if (StringUtils.isBlank(itemLot4)) {
						itemHealthStoreCategoryMap.put(containerCode, itemHealthStoreCategory);
					} else {
						if (!itemLot4.equals(itemHealthStoreCategory)) {
							throw new BizException(
									String.format("存储分类不同不可选同容器,容器[%s],商品[%s]", containerCode, rqcLinesDTO.getItemName()));
						}
					}
					if (!StringUtils.isBlank(storeTemperature)) {
						if (StringUtils.isBlank(itemLot6)) {
							itemStoreTempMap.put(containerCode, storeTemperature);
						} else {
							if (!itemLot6.equals(storeTemperature)) {
								throw new BizException(
										String.format("存储条件不同不可选同容器,容器[%s],商品[%s]", containerCode, rqcLinesDTO.getItemName()));
							}
						}
					}
				}
				// 设备库别校验容器
				String whAreaCategoryCode = rqcLinesDTO.getWhAreaCategoryCode();
				String productionDateStr = "";
				if(rqcLinesDTO.getBatchProductionDate()!=null){
					productionDateStr = DateUtils.format(rqcLinesDTO.getBatchProductionDate(),"yyyy-MM-dd");
				}
				String expiredDateStr = "";
				if(rqcLinesDTO.getBatchExpiredDate()!=null){
					expiredDateStr = DateUtils.format(rqcLinesDTO.getBatchExpiredDate(),"yyyy-MM-dd");
				}
				String itemId = rqcLinesDTO.getItemId();
				String itemName = rqcLinesDTO.getItemName();
				String manufacturerLotNum = rqcLinesDTO.getManufacturerLotNum();
//				if (!StringUtils.isBlank(whAreaCategoryCode) && BizConstant.AGVK.equals(whAreaCategoryCode)) {
				if (!StringUtils.isBlank(whAreaCategoryCode) && ("MJK".equals(whAreaCategoryCode) ||"AGVZ".equals(whAreaCategoryCode) ||"AGVL".equals(whAreaCategoryCode)) ) {
					// 校验是否在同一容器,商品id+商品批号
					if (!StringUtils.isBlank(containerCode) && !"N/A".equals(containerCode)) {
						String itemLot = cc.get(containerCode);
						if (StringUtils.isBlank(itemLot)) {
							cc.put(containerCode, itemId + manufacturerLotNum + productionDateStr + expiredDateStr);
						} else {
							if (!itemLot.equals(itemId + manufacturerLotNum + productionDateStr + expiredDateStr)) {
								throw new BizException(String.format("AGV库区不同品批不可选同容器,容器[%s],商品[%s],批号[%s]",
										containerCode, itemName, manufacturerLotNum));
							}
						}
					}
				}else{
					Map<String,String> dd = new HashMap<>();
					BigDecimal oddCaseQty = rqcLinesDTO.getOddCaseQty();
					BigDecimal oddPieceQty1 = rqcLinesDTO.getOddPieceQty();
					if(oddCaseQty.compareTo(BigDecimal.ZERO)>0&&oddPieceQty1.compareTo(BigDecimal.ZERO)==0){
						String itemLot = dd.get(containerCode);
						if (StringUtils.isBlank(itemLot)) {
							dd.put(containerCode, manufacturerLotNum + productionDateStr + expiredDateStr);
						} else {
							if (!itemLot.equals(manufacturerLotNum + productionDateStr + expiredDateStr)) {
								throw new BizException(String.format("同容器整件收货可混品不可混批,容器[%s],商品[%s],批号[%s]",
										containerCode, itemName, manufacturerLotNum));
							}
						}
					}
					if (!StringUtils.isBlank(whAreaCategoryCode) && BizConstant.NHK.equals(whAreaCategoryCode)) {
						rqcLinesDTO.setStockStatus("1");
					}
				}

				// 校验整件零散不能同容器
				if (!StringUtils.isBlank(containerCode) && !"N/A".equals(containerCode)) {
					if (BigDecimal.ZERO.compareTo(caseQty) == 0) {
						// 散件
						zjContainerCode.add(containerCode);
					} else if (BigDecimal.ZERO.compareTo(caseQty) == -1
							&& BigDecimal.ZERO.compareTo(oddPieceQty) == 0) {
						// 整件
						sjContainerCode.add(containerCode);
					}
				}
			}
			String rcvType = rqcLinesDTO.getRcvType();
			Date batchExpiredDate = rqcLinesDTO.getBatchExpiredDate();
			if (batchExpiredDate == null)
				batchExpiredDate = now;
			Long subtract = DateUtils.subtract(now, batchExpiredDate, ChronoUnit.DAYS);
			if (rcvType.equals(2) && subtract <= 0) {
				// 过期了,入不合格库
				// 无需双人质检
				excuteInsert(taskIds, list, list3, rqcLinesDTO, editFlag, userDTO, row, now, taskRqcId, times);
				continue;
			}

			String stockStatus = rqcLinesDTO.getStockStatus();
			if (StringUtils.isBlank(stockStatus))
				stockStatus = rqcLinesDTO.getQcResult1();

			rqcLinesDTO.setStockStatus(stockStatus);
			AssertUtils.isNotBlank(stockStatus, String.format("第[%d]行数据的质检结论为空", row));

			// 验证结论是否选择正确
			RcvCommonLine rcl = convert2RcvCommonLine(rcvType, rqcLinesDTO);
			clList.add(rcl);

			if (times == null)
				times = 0;

			// Step1: 判断质检结论是否合格
			if (stockStatus.equals("0")) {
				// 合格处理
				// Step2: 判断是否复检
				Integer isRechecked = rqcLinesDTO.getIsRechecked();
				if (isRechecked != null && 1 == isRechecked) {
					// 是复检过来的
					// 直接新增,向下推送任务
					excuteInsert(taskIds, list, list3, rqcLinesDTO, editFlag, userDTO, row, now, taskRqcId, times);

				} else {
					// 不是复检过来的
					// Step3: 商品是否双人质检
					Integer itemHealthIsDouble = rqcLinesDTO.getItemHealthIsDouble();
					if (!isAuto) {
						if (itemHealthIsDouble != null && itemHealthIsDouble == 1) {
							// 1是双人
							if (times != null && 2 == times) {
								taskIds.add(taskRqcId);
								continue;
							} else if (times != null && 1 == times) {
								// 第二次质检
								taskIds.add(taskRqcId);
								rqcLinesDTO.setTimes(times + 1);
								Date qcDate2 = rqcLinesDTO.getQcDate2();
								String qcOpcode2 = rqcLinesDTO.getQcOpcode2();
								String qcReason2 = rqcLinesDTO.getQcReason2();
								String qcResult2 = rqcLinesDTO.getQcResult2();
								String qcStatus2 = rqcLinesDTO.getQcStatus2();
								if (qcDate2 == null) {
									rqcLinesDTO.setQcDate2(now);
								}
								if (StringUtils.isBlank(qcStatus2)) {
									rqcLinesDTO.setQcStatus2("1");
								}
								if (StringUtils.isBlank(qcOpcode2)) {
									rqcLinesDTO.setQcOpcode2(userDTO.getUsername());
								}
								if (StringUtils.isBlank(qcReason2)) {
									rqcLinesDTO.setQcReason2(rqcLinesDTO.getHandlingReason());
								}
								if (StringUtils.isBlank(qcResult2)) {
									rqcLinesDTO.setQcResult2(rqcLinesDTO.getStockStatus());
								}
								list2.add(rqcLinesDTO);
								list3.add(rqcLinesDTO);
							} else {
								// 第一次质检
								// 判断是否双人质检
								this.buildDefaultField(rqcLinesDTO, editFlag, userDTO);
								this.vaildateModel(rqcLinesDTO, editFlag, userDTO, row, validator,
										SERVICE_MSG + OperationConstant.BATCH_ADD_OPERATION);
								RqcLines lines = new RqcLines();
								BeanUtils.copyProperties(rqcLinesDTO, lines);
								this.buildField(lines, editFlag, userDTO, now);
								lines.setTimes(times + 1); // 次数加1
								list.add(lines);
								// 双人第一次质检
								taskIds3.add(taskRqcId);
							}
						} else {
							// 不是双人
							// 直接新增,向下推送任务
							excuteInsert(taskIds, list, list3, rqcLinesDTO, editFlag, userDTO, row, now, taskRqcId,
									times);
						}
					} else {
						// 自动生成单据
						excuteInsert(taskIds, list, list3, rqcLinesDTO, editFlag, userDTO, row, now, taskRqcId, times);
					}

				}
			} else {
				// 其他结论处理
				Integer isRechecked = rqcLinesDTO.getIsRechecked();
				if (isRechecked != null && 1 == isRechecked && rqcLinesDTO.getStockStatus().equals("2")) {
					// 是复检过来的但是结论是待处理,需要抛错
					throw new BizException(String.format("第[%d]行,数据已经经过复检,结论不可填待处理时选择!请检查重试!", row));
				}
				// 直接新增,向下推送任务
				excuteInsert(taskIds, list, list3, rqcLinesDTO, editFlag, userDTO, row, now, taskRqcId, times);

			}
		}

		ContainerQueryVO cVO = new ContainerQueryVO();
		cVO.setWarehouseId(warehouseId);
		cVO.setEnterpriseId(userDTO.getEnterpriseId());
		try {
			// 容器释放
			if (oldContainerCodeList.size()>0) {
				cVO.setContainerCodeList(oldContainerCodeList);
				baseWmsWarehouseCaller.release(cVO);
			}
			// 容器占用
			if (newContainerCodeList.size()>0) {
				cVO.setContainerCodeList(newContainerCodeList);
				baseWmsWarehouseCaller.used(cVO);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		iqueryMap.put("queryMap", iqList);
		iqueryMap.put("type", "in");
		iqueryMap.put("cargoOwnerId", rqcLinesDTOList.get(0).getMtlOwnerId());
		excuteVaildteItem(iqueryMap, rqcLinesDTOList, userDTO, now);

		if (!StringUtils.isBlank(businessControlValue) && businessControlValue.equals("1")) {
			// 整件散件不可同容器
			if (!ObjectUtils.isNull(zjContainerCode) && !ObjectUtils.isNull(sjContainerCode)) {
				Collection intersection = CollectionUtils.intersection(zjContainerCode, sjContainerCode);
				if (!ObjectUtils.isNull(intersection)) {
					throw new BizException("整件散件容器不可选一样的!" + intersection.toString());
				}
			}
		}

		// 2. 保存质检行
		excuteBatchSave(list);

		// 2.1 更新二次质检数据
		excuteBatchUpdate(list2, userDTO);

		// 3. 更新质检任务池状态(需要根据双人质检来)
		this.updateTaskPoolStatus(taskIds);

		// 3.1 更新质检执行者
		this.updateTaskPoolExcuter(taskIds2);

		// 3.2 执行过期处理
		if (!isAuto) {
			excuteExpirDate(list3, now);
		}

		// 3.3 更新双人第一次质检来源id
		this.updateTaskPoolPreNode(taskIds3, userDTO);

		// 4. 推送任务池
		this.excutePushTaskPool(list, list2, list3, isAuto);
		return true;
	}

	private void vaildateConclusion(List<RcvCommonLine> clList, List<RqcLinesDTO> rqcLinesDTOList) {
		// 校验结论
		List<RcvCommonLine> conclusion = rcvLinesService.getConclusion(clList);
		if (ObjectUtils.isNull(conclusion)) {
			return;
		}
		Map<String, List<RcvCommonLine>> collect = conclusion.stream()
				.collect(Collectors.groupingBy(RcvCommonLine::getRefId));
		int row = 0;
		for (RqcLinesDTO rqcLinesDTO : rqcLinesDTOList) {
			row++;
			String rqcLineId = rqcLinesDTO.getRqcLineId();
			List<RcvCommonLine> list = collect.get(rqcLineId);
			if (ObjectUtils.isNull(list)) {
				continue;
			}
			RcvCommonLine rcvCommonLine = list.get(0);
			String stockStatus = rqcLinesDTO.getStockStatus();
			List<Map<String, String>> conclusionList = rcvCommonLine.getConclusionList();
			if (!ObjectUtils.isNull(conclusionList)) {
				List<String> conclusionCodes = new ArrayList<>();
				for (Map<String, String> map : conclusionList) {
					String string = map.get("code");
					conclusionCodes.add(string);
				}
				if (!conclusionCodes.contains(stockStatus)) {
					throw new BizException(String.format("第[%d]行,结论选择有误!请重新选择!", row));
				}
			}
		}

	}

	private RcvCommonLine convert2RcvCommonLine(String rcvType, RqcLinesDTO rqcLinesDTO) {
		// 收货行转换为结论校验行
		RcvCommonLine rcl = new RcvCommonLine();
		rcl.setBatchExpiredDate(rqcLinesDTO.getBatchExpiredDate());
		rcl.setMtlOwnerId(rqcLinesDTO.getMtlOwnerId());
		rcl.setWarehouseId(rqcLinesDTO.getWarehouseId());
		rcl.setRcvType(rcvType);
		rcl.setRefId(rqcLinesDTO.getTaskRqcId());
		rcl.setRefType(rqcLinesDTO.getRefType());
		return rcl;
	}

	private void excuteVaildteItem(Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO, Date now) {
		RqcLinesDTO linesDTO = rqcLinesDTOList.get(0);
		String mtlOwnerId = linesDTO.getMtlOwnerId();
		Map<String, Object> queryMap = new HashMap<>();
		queryMap.put("cargoOwnerId", mtlOwnerId);
		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 flag1 = (String) map.get("vaildateItemLicense");
			String flag2 = (String) map.get("vaildateItemVol");
			String flag3 = (String) map.get("vaildateItemCategory");
			String flag4 = (String) map.get("vaildateItemInbound");
			String flag5 = (String) map.get("vaildateCargoOwnerScop");
			String flag6 = (String) map.get("vaildateContainer");
			// 校验商品证照
			vaildateItemLicense(flag1, iqueryMap, rqcLinesDTOList, userDTO, now);
			// 校验商品体积信息
//			vaildateItemVol(flag2, iqueryMap, rqcLinesDTOList, userDTO, now);
			// 校验商品大类是否维护
//			vaildateItemCategory(flag3, iqueryMap, rqcLinesDTOList, userDTO, now);
			// 校验商品是否停售召回
			vaildateItemInbound(flag4, iqueryMap, rqcLinesDTOList, userDTO, now);
			// 校验货主-商品大类关系(即货主的经营范围)
//			vaildateCargoOwnerScop(flag5, iqueryMap, rqcLinesDTOList, userDTO, now);
			// 校验入库商品绑定容器是否正确
//			vaildateItemContainer(flag6, iqueryMap, rqcLinesDTOList, userDTO, now);

		}

	}

	private void vaildateItemContainer(String flag6, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// TODO Auto-generated method stub

	}

	private void vaildateCargoOwnerScop(String flag5, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// TODO Auto-generated method stub

	}

	private void vaildateItemInbound(String flag4, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// 校验商品是否停售召回
		if (!StringUtils.isBlank(flag4) && "1".equals(flag4)) {
			RestMessage<Object> vaildatePurchaseAndSales = null;
			try {
				vaildatePurchaseAndSales = baseItemRemoteCaller.vaildatePurchaseAndSales(iqueryMap);
			} catch (Exception e) {
				logger.error("调用远程商品服务校验商品是否召回停售失败,原因{}", e.getMessage());
			}
			if (vaildatePurchaseAndSales != null) {
				if (!vaildatePurchaseAndSales.isSuccess()) {
					throw new BizException("校验商品是否停售召回失败,原因->" + vaildatePurchaseAndSales.getMessage());
				} else {
					Map rMap = (Map) vaildatePurchaseAndSales.getData();
					List<Map> queryList = (List) rMap.get("queryMap");
					for (Map map2 : queryList) {
						Integer row = (Integer) map2.get("refId");
						Boolean flag = (Boolean) map2.get("flag");
						String itemId = (String) map2.get("itemId");
						String message = (String) map2.get("message");
						if (!flag) {
							throw new BizException(
									String.format("第[%d]行,商品id[%s],商品停售,召回校验失败.原因->[%s]", row, itemId, message));
						}
					}
				}
			}
		}

	}

	private void vaildateItemCategory(String flag3, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// TODO Auto-generated method stub

	}

	private void vaildateItemVol(String flag2, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// TODO Auto-generated method stub

	}

	private void vaildateItemLicense(String flag1, Map iqueryMap, List<RqcLinesDTO> rqcLinesDTOList, UserDTO userDTO,
			Date now) {
		// 校验商品证照
		if (!StringUtils.isBlank(flag1) && "1".equals(flag1)) {
			RestMessage batchVaildateCertificate = null;
			try {
				batchVaildateCertificate = baseItemRemoteCaller.batchVaildateCertificate(iqueryMap);
			} catch (Exception e) {
				logger.error("调用远程商品服务失败,原因{}", e.getMessage());
			}
			if (batchVaildateCertificate != null) {
				if (!batchVaildateCertificate.isSuccess()) {
					throw new BizException("校验商品失败,原因->" + batchVaildateCertificate.getMessage());
				} else {
					Map rMap = (Map) batchVaildateCertificate.getData();
					List<Map> queryList = (List) rMap.get("queryMap");
					for (Map map2 : queryList) {
						Integer row = (Integer) map2.get("refId");
						Boolean flag = (Boolean) map2.get("flag");
						String itemId = (String) map2.get("itemId");
						String message = (String) map2.get("message");
						if (!flag) {
							throw new BizException(
									String.format("第[%d]行,商品id[%s],证照效期校验失败.原因->[%s]", row, itemId, message));
						}
					}
				}
			}
		}
	}

	private void vaildateAreaCategory(RqcLinesDTO rqcLinesDTO, int row) {
		String whAreaCategory = rqcLinesDTO.getWhAreaCategory();
		if (!StringUtils.isBlank(whAreaCategory)) {
			String caseOrPiece = this.getCaseOrPiece(rqcLinesDTO);
			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(RqcLinesDTO target) {
		// 是否整散
		BigDecimal pieceQty = target.getPieceQty();
		if(pieceQty!=null){
			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";
		}
		return null;
	}

	private void updateTaskPoolPreNode(List<String> taskIds3, UserDTO userDTO) {
		if (ObjectUtils.isNull(taskIds3)) {
			return;
		}
		for (String taskId : taskIds3) {
			this.taskQcDetailMapper.updatePreNodeLineId(taskId, userDTO.getUsername());
		}
	}

	/**
	 * 自动生成质检行信息
	 */
	@Transactional
	@TxTransaction(isStart = true)
	@Override
	public Object batchAddAuto(List<RqcLinesDTO> rqcLinesDTOList, RqcHeadersDTO rqcHeadersDTO, UserDTO userDTO,
			Date date, boolean isPad) {
		String masterId = rqcHeadersDTO.getRqcHeaderId();
		Integer isInstockPrint = rqcHeadersDTO.getIsInstockPrint();
		String autoBillNum = rqcHeadersDTO.getAutoBillNum();
		this.batchAdd(rqcLinesDTOList, masterId, userDTO, date, isInstockPrint, autoBillNum, false, true, isPad);
		return null;
	}
	@Override
	public Map<RqcLinesDTO,List<RcvLineResult>> recommendRoom(List<RqcLinesDTO> dtoList) throws Exception {
		logger.info(String.format("质检验收获取库别策略请求参数【%s】", JsonUtils.toString(dtoList)));
		Assert.isFalse(dtoList == null || dtoList.size()==0, "入参不能为空");
		Assert.isFalse(StringUtils.isBlank(dtoList.get(0).getWarehouseId()), "仓id不能为空");
		Assert.isFalse(StringUtils.isBlank(dtoList.get(0).getMtlOwnerId()), "货主id不能为空");
		String enterpriseId = userUtils.getEnterpriseId();
		Map<RqcLinesDTO,List<RcvLineResult>> result= Maps.newHashMap();
		List<RcvLineResult> rcvLineResults= Lists.newArrayList();
		// Step1: 远程找寻策略
		RestMessage<StrategyDTO> strategyResult = null;
		try {
			strategyResult = strategyClient.getStrategyDTO(enterpriseId, "RcvAreaCategoryChoose", dtoList.get(0).getMtlOwnerId(), dtoList.get(0).getWarehouseId());
		} catch (Exception e) {
			logger.error("质检验收获取库别策略-获取可用策略发生异常->", e);
		}
		logger.info(String.format("质检验收获取库别策略-获取可用策略【%s】", JsonUtils.toString(strategyResult)));
		Assert.isFalse(strategyResult == null, String.format("质检验收获取库别策略-获取可用策略返回空【%s】", JsonUtils.toString(dtoList)));
		StrategyDTO strategyDTO = strategyResult.getData();
		Strategy strategy = null;
		try {
			strategy = strategyDTO.createStrategy();
		} catch (Exception e) {
			logger.error("质检验收获取库别策略-策略创建失败->", e);
		}
		Assert.isFalse(strategy == null, String.format("质检验收获取库别策略-策略创建返回空【%s】", JsonUtils.toString(dtoList)));
		// Step2: 获取具体策略
		if (ObjectUtils.isNotNull(strategy)) {
			for(RqcLinesDTO dto : dtoList){
				Assert.isFalse(StringUtils.isBlank(dto.getRcvType()), "单据类型不能为空");
				Assert.isFalse(StringUtils.isBlank(dto.getStockStatus()), "质检结论不能为空");
				WhAreaCategoryContext context = new WhAreaCategoryContext();
				WhAreaCategoryContext.RcvLineData rcvLineData = context.new RcvLineData();
				rcvLineData.setBillType(dto.getRcvType());
				rcvLineData.setStorageStatus(dto.getStockStatus());
				rcvLineData.setDataSource("1");
				String isCase=getCaseOrPiece(dto);
				if(!StringUtils.isBlank(isCase)){
					rcvLineData.setIsCase(isCase);
				}
				if(dto.getPieceQty()!=null && dto.getConversionRate()!=null){
					BigDecimal oddCaseQty = dto.getPieceQty().divide(dto.getConversionRate(), 0, RoundingMode.DOWN);
					rcvLineData.setQty(oddCaseQty.doubleValue());
				}
				try {
					context.setRcvLineData(rcvLineData);
					logger.info(String.format("收货策略执行参数[%s]", JsonUtils.toString(context)));
					context.setTargetAreaCategoryCodes(Lists.newArrayList());
					strategy.execute(context);
				} catch (Exception e) {
					logger.error("获取入库库别策略-策略执行失败->", e);
				}
				boolean completed = context.completed();
				Assert.isFalse(!completed, String.format("获取入库库别策略-策略执行失败发生返回失败【%s】", JsonUtils.toString(dto)));
				// 找到匹配的策略
				List<String> targetAreaCategoryCodes = context.getTargetAreaCategoryCodes();
				logger.info(String.format("获取入库库别策略,推荐库别[%s]",JsonUtils.toString(targetAreaCategoryCodes)));
				Assert.isFalse(targetAreaCategoryCodes==null || targetAreaCategoryCodes.size()==0, String.format("获取入库库别策略-策略执行未匹配到库别【%s】", JsonUtils.toString(dto)));
				//获取库别名称
				for(String targetAreaCategoryCode : targetAreaCategoryCodes){
					RcvLineResult rcvLineResult=new RcvLineResult();
					rcvLineResult.setWarehouseRoomCode(targetAreaCategoryCode);
					switch (targetAreaCategoryCode) {
						case "ZJK":
							rcvLineResult.setWarehouseRoomName("整件库");
							break;
						case "MJK":
							rcvLineResult.setWarehouseRoomName("四向库(密集库)");
							break;
						case "NHK":
							rcvLineResult.setWarehouseRoomName("不合格库");
							break;
						case "PDK":
							rcvLineResult.setWarehouseRoomName("盘点库");
							break;
						case "ADJ":
							rcvLineResult.setWarehouseRoomName("调整库");
							break;
						case "ZTK":
							rcvLineResult.setWarehouseRoomName("直通库");
							break;
						case "AGVZ":
							rcvLineResult.setWarehouseRoomName("AGV整件库");
							break;
						case "AGVL":
							rcvLineResult.setWarehouseRoomName("AGV拆零库");
							break;
						case "ZYK":
							rcvLineResult.setWarehouseRoomName("中药库");
							break;
						case "WLK":
							rcvLineResult.setWarehouseRoomName("物料库");
							break;
						default:
							break;
					}
					rcvLineResults.add(rcvLineResult);
				}
				result.put(dto,rcvLineResults);
			}
		}
		return result;
	}

    @Override
	public void checkRfRqcQty(List<RqcLinesDTO> list) {
		for(RqcLinesDTO dto : list){
			AssertUtils.isNotTrue(dto == null, "入参不能为空");
			AssertUtils.isNotTrue(StringUtils.isBlank(dto.getItemId()), "商品id不能为空");
			AssertUtils.isNotTrue(dto.getPieceQty()==null, "质检数量不能为空");
			AssertUtils.isNotTrue(dto.getConversionRate()==null, "质检包装数量不能为空");
			AssertUtils.isNotTrue(dto.getOddCaseQty()==null, "质检整箱数不能为空");
			AssertUtils.isNotTrue(dto.getOddPieceQty()==null, "质检零散数不能为空");
			AssertUtils.isNotTrue(StringUtils.isBlank(dto.getStockStatus()), "质检零散数不能为空");
			BigDecimal pieceQty = dto.getPieceQty();
			BigDecimal conversionRate = dto.getConversionRate();
			BigDecimal oddCaseQty = pieceQty.divide(conversionRate, 0, RoundingMode.DOWN);
			BigDecimal oddPieceQty = pieceQty.subtract(oddCaseQty.multiply(conversionRate));
			Assert.isFalse(oddCaseQty.compareTo(dto.getOddCaseQty())!=0, "根据数量计算的质检整箱数与页面传入不一致,请检查");
			Assert.isFalse(oddPieceQty.compareTo(dto.getOddPieceQty())!=0, "根据数量计算的质检零散数与页面传入不一致,请检查");
		}
	}
}
