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

import cn.hutool.core.date.DatePattern;
import com.prolog.common.util.ToolKits;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.item.model.BaseMtlItemUomConversions;
import com.prolog.cs.biz.inbound.constant.BizConstant;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesProfilesMapper;
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.rcv.RcvHDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvLinesDTO;
import com.prolog.cs.biz.inbound.dto.rqc.RqcLinesDTO;
import com.prolog.cs.biz.inbound.dto.rqc.RqcReLinesDTO;
import com.prolog.cs.biz.inbound.dto.rqc.RqcRechekLinesDTO;
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.rcv.RcvLinesProfiles;
import com.prolog.cs.biz.inbound.model.task.TaskQcDetail;
import com.prolog.cs.biz.inbound.remote.BaseItemRemoteCaller;
import com.prolog.cs.biz.inbound.service.SupervisionCodeService;
import com.prolog.cs.biz.inbound.service.impl.BaseServiceImpl;
import com.prolog.cs.biz.inbound.service.impl.processor.Helper.HostedHelper;
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.RcvQueryVO;
import com.prolog.cs.biz.inbound.vo.task.TaskQcDetailQueryVO;
import com.prolog.framework.authority.core.dto.UserBizModel;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.Criteria;
import com.prolog.framework.core.restriction.Order;
import com.prolog.framework.core.restriction.Restriction;
import com.prolog.framework.core.restriction.Restrictions;
import com.prolog.framework.dao.util.PageUtils;
import com.prolog.framework.utils.*;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

//import java.math.RoundingMode;

@Service
public class TaskQcDetailServiceImpl extends BaseServiceImpl<TaskQcDetail> implements TaskQcDetailService {

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

	@Resource
	private TaskQcDetailMapper mapper;

	@Resource
	private UserUtils userUtils;

	@Resource
	private BaseItemRemoteCaller itemClient;

	@Resource
	private SupervisionCodeService supervisionCodeService;

	@Resource
	private RqcLinesMapper rqcLinesMapper;

	@Resource
	private RcvLinesMapper rcvLinesMapper;

	@Resource
	private RcvLinesProfilesMapper rcvLinesProfilesMapper;

	@Value("${prolog.wms.enableDefaultCargoOwnerSearch:false}")
	private Boolean enableDefaultCargoOwnerSearch;

	@Resource
	private HostedHelper hostedHelper;

	@Resource
	private TaskQcDetailMapper taskQcDetailMapper;

	@Resource
	private BaseItemRemoteCaller itemRemoteCaller;
	@Override
	public Object add(TaskQcDetailDTO taskQcDetailDTO) {
		// TODO vaildate
		UserDTO userDTO = userUtils.getUserDTO();
		TaskQcDetail taskQcDetail = new TaskQcDetail();
		BeanUtils.copyProperties(taskQcDetailDTO, taskQcDetail);
		this.vaildateModel(taskQcDetail, false, userDTO);
		this.buildField(taskQcDetail, false, userDTO);
		this.mapper.save(taskQcDetail);
		return "";
	}

	@Override
	public Object edit(String pkId, TaskQcDetailDTO taskQcDetailDTO) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		TaskQcDetail taskQcDetail = new TaskQcDetail();
		BeanUtils.copyProperties(taskQcDetailDTO, taskQcDetail);
		this.vaildateModel(taskQcDetail, true, userDTO);
		this.buildField(taskQcDetail, true, userDTO);
		this.mapper.updateWithValidate(taskQcDetail,
				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, TaskQcDetail.class));
		return "";
	}

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

	@Override
	public Page<TaskQcDetailDTO> findList(TaskQcDetailDTO taskQcDetailDTO, PageParam pageParam) {

		Criteria criteria = this.buildPageParam(pageParam, true, null, TaskQcDetail.class);
		Restriction r = buildCondition(taskQcDetailDTO);
		// 任务条件 (余量>0 作废) 状态为可用,rcvHeaderId,若是双人质检,则执行者不能是当前的登录用户
//		Restriction and1 = Restrictions.and(Restrictions.gt("remainQty", 0), Restrictions.eq("status", "1"));
		Restriction and1 = Restrictions.eq("status", "1");
		Restriction eq1 = Restrictions.eq("itemHealthIsDouble", 1);
		Restriction eq2 = Restrictions.eq("itemHealthIsDouble", 0);
		Restriction ne = Restrictions.ne("executor", userUtils.getUserId());
		Restriction or1 = Restrictions.or(Restrictions.and(eq1, ne), eq2);
		Restriction condition = Restrictions.and(r, and1, or1);
		criteria.setRestriction(condition);
		this.startPage(pageParam);
		List<TaskQcDetail> list = this.mapper.findByCriteria(criteria);
		Page<TaskQcDetail> page = PageUtils.getPage(list);
		Page<TaskQcDetailDTO> page2 = this.buildPage(page, (p) -> {
			TaskQcDetailDTO target = new TaskQcDetailDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		});
		return page2;

	}

	@Override
	@Transactional
	public Object batchAdd(List<TaskQcDetailDTO> taskQcDetailDTOList) {
		// TODO
		UserDTO userDTO = userUtils.getUserDTO();
		for (TaskQcDetailDTO taskQcDetailDTO : taskQcDetailDTOList) {
			TaskQcDetail taskQcDetail = new TaskQcDetail();
			BeanUtils.copyProperties(taskQcDetailDTO, taskQcDetail);
			this.vaildateModel(taskQcDetail, false, userDTO);
			this.buildField(taskQcDetail, false, userDTO);
			this.mapper.save(taskQcDetail);
		}
		return "";
	}

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

	@Override
	public List<TaskQcDetailDTO> findAll(TaskQcDetailDTO taskQcDetailDTO) {
		// TODO
		Criteria criteria = Criteria.forClass(TaskQcDetail.class);
		TaskQcDetailDTO condition = taskQcDetailDTO;
		Restriction r = buildCondition(condition);
		// 状态为未质检
		Restriction or = Restrictions.eq("status", "1");
//		Restriction or = Restrictions.or(Restrictions.gt("remainQty", 0), Restrictions.eq("status", "1"));
		Restriction and = Restrictions.and(r, or);
		criteria.setRestriction(and);
		Order order = Order.newInstance().desc("gmtModified");
		criteria.setOrder(order);
		List<TaskQcDetail> list = this.mapper.findByCriteria(criteria);
		List<TaskQcDetailDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream().map(p -> {
			TaskQcDetailDTO target = new TaskQcDetailDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		}).collect(Collectors.toList());
		return collect;
	}

	@Override
	public TaskQcDetailDTO findByPkId(String pkId) {
		// TODO
		TaskQcDetail taskQcDetail = this.findById(pkId);
		AssertUtils.notNull(taskQcDetail, "TaskQcDetail model empty!");
		TaskQcDetailDTO taskQcDetailDTO = new TaskQcDetailDTO();
		BeanUtils.copyProperties(taskQcDetail, taskQcDetailDTO);
		return taskQcDetailDTO;
	}

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

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

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

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

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

	private Restriction buildCondition(TaskQcDetailDTO taskQcDetailDTO) {
		Restriction r0 = Restrictions.eq("enterpriseId", userUtils.getEnterpriseId());
		if (ObjectUtils.isNull(taskQcDetailDTO))
			return r0;

		// 构建查询条件
		String batchNum = taskQcDetailDTO.getBatchNum();
		String mtlOwnerId = taskQcDetailDTO.getMtlOwnerId();
		String warehouseId = taskQcDetailDTO.getWarehouseId();
		String rcvHeaderId = taskQcDetailDTO.getRcvHeaderId();
		String rcvLineId = taskQcDetailDTO.getRcvLineId();
		String itemId = taskQcDetailDTO.getItemId();

		Restriction r1 = StringUtils.isBlank(mtlOwnerId) ? null : Restrictions.eq("mtlOwnerId", mtlOwnerId);
		Restriction r2 = StringUtils.isBlank(warehouseId) ? null : Restrictions.eq("warehouseId", warehouseId);
		Restriction r3 = StringUtils.isBlank(rcvHeaderId) ? null : Restrictions.eq("rcvHeaderId", rcvHeaderId);
		Restriction r4 = StringUtils.isBlank(rcvLineId) ? null : Restrictions.eq("rcvLineId", rcvLineId);
		Restriction r5 = StringUtils.isBlank(itemId) ? null : Restrictions.eq("itemId", itemId);
		Restriction r6 = StringUtils.isBlank(batchNum) ? null : Restrictions.like("batchNum", "%" + batchNum + "%");

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

	@Override
	public Object excuteTask(List<RcvLinesDTO> rcvLinesDTO, String mtlOwnerId, String warehouseId, boolean isAuto) {
		// 收货行第一次入质检任务池
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		for (RcvLinesDTO rcvLinesDTO2 : rcvLinesDTO) {
			TaskQcDetail taskQcDetail = new TaskQcDetail();
			this.buildDefaultField(taskQcDetail, false, userDTO, now);
			BeanUtils.copyProperties(rcvLinesDTO2, taskQcDetail);
			taskQcDetail.setRcvLineId(rcvLinesDTO2.getRcvLineId());
			taskQcDetail.setSrcBillType(rcvLinesDTO2.getSrcBillType());
			this.buildField(taskQcDetail, false, userDTO, now);
			taskQcDetail.setWarehouseId(warehouseId);
			taskQcDetail.setMtlOwnerId(mtlOwnerId);

			// 需要判断是第几次质检
			taskQcDetail.setTimes(0); // 默认第一次质检
			taskQcDetail.setAsnHeaderId(rcvLinesDTO2.getAsnHeaderId());
			taskQcDetail.setAsnLineId(rcvLinesDTO2.getAsnLineId());
			taskQcDetail.setSrcHeaderId(rcvLinesDTO2.getSrcHeaderId());
			taskQcDetail.setSrcLineId(rcvLinesDTO2.getSrcLineId());
			taskQcDetail.setDataVersion(0);
			// 计算出包装数量
//			BigDecimal oddCaseQty = rcvLinesDTO2.getOddCaseQty();
//			taskQcDetail.setQty(oddCaseQty);

			// 库别
//			String warehouseAreaCategory = rcvLinesDTO2.getWarehouseAreaCategory();
			// 类型
			taskQcDetail.setRefType(0);
			taskQcDetail.setRefLineId(rcvLinesDTO2.getRcvLineId());
			// 暂存结论
			taskQcDetail.setResult(rcvLinesDTO2.getStockStatus());
			taskQcDetail.setIsRechecked(0);
			taskQcDetail.setExecutor(null); // 无执行者
			this.mapper.save(taskQcDetail);
		}
		return true;
	}

	private void buildDefaultField(TaskQcDetail taskQcDetail, boolean editFlag, UserDTO userDTO, Date now) {
		String activeFlag = taskQcDetail.getActiveFlag();
		if (!editFlag && ObjectUtils.isNull(activeFlag)) {
			taskQcDetail.setActiveFlag("1"); // 默认作业标识可用
		}
		taskQcDetail.setStatus("1"); // 默认可执行
//		String status = taskQcDetail.getStatus();
//		if (!editFlag && ObjectUtils.isNull(status)) {
//			taskQcDetail.setStatus("1"); // 默认待质检(?字义不明确)
//		}
		Integer isSpilt = taskQcDetail.getIsSpilt();
		if (!editFlag && ObjectUtils.isNull(isSpilt)) {
			taskQcDetail.setIsSpilt(0);
		}
		if (!editFlag) {
			taskQcDetail.setDataVersion(0);
		}

	}

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

	@Override
	public Object excuteTask2(List<RqcLinesDTO> rqcLinesList) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object excuteTask33(List<RqcRechekLinesDTO> rqcRechekLinesList, String conclusion, int times) {
		// 复检入质检任务池
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		for (RqcRechekLinesDTO rqcRechekLinesDTO : rqcRechekLinesList) {

			TaskQcDetail taskQcDetail = new TaskQcDetail();
			BeanUtils.copyProperties(rqcRechekLinesDTO, taskQcDetail);
			this.buildDefaultField(taskQcDetail, false, userDTO, now);
			// 复检字段缺失补充 TODO
			this.buildField(taskQcDetail, false, userDTO, now);
//			taskQcDetail.setExecutor(userDTO.getId());
			taskQcDetail.setTimes(0);
			taskQcDetail.setDataVersion(0);
			// 需要判断是第几次质检
//			taskQcDetail.setTimes(1);
//			taskQcDetail.setAsnHeaderId(rqcRechekLinesDTO.get);
//			taskQcDetail.setAsnLineId(rqcRechekLinesDTO.getSrcAsnLineId());
//			taskQcDetail.setSourceHeaderId(rqcRechekLinesDTO.getSrcHeaderIds());
//			taskQcDetail.setSourceLineId(rqcRechekLinesDTO.getSrcLineId());
			taskQcDetail.setExecutor(null); // 无执行者
			this.mapper.save(taskQcDetail);
		}
		return true;
	}

	@Override
	public Object excuteTask3(List<RqcReLinesDTO> rqcReLinesList, String conclusion, int times, boolean isAuto,
							  String regValue, String warehouserId) {
		// 复检入质检任务池
		UserDTO userDTO = userUtils.getUserDTO();
		Date now = new Date();
		// 需要代管出库的明细
		List<RqcReLinesDTO> outHosted = new ArrayList<>();
		for (RqcReLinesDTO rqcReLinesDTO : rqcReLinesList) {
			// 如果 操作来源单类型为 3-收货待处理 或 4-质检待处理 且 业务参数是否进入代管子流程为1，则需要代管出库
			if (("1".equals(rqcReLinesDTO.getHostedStatus()) || "2".equals(rqcReLinesDTO.getHostedStatus()))
					&& ObjectUtils.isNotNull(regValue) && "1".equals(regValue)) {
				outHosted.add(rqcReLinesDTO);
			}

			TaskQcDetail taskQcDetail = new TaskQcDetail();
			BeanUtils.copyProperties(rqcReLinesDTO, taskQcDetail);
			this.buildDefaultField(taskQcDetail, false, userDTO, now);
			// 复检字段缺失补充 TODO
			this.buildField(taskQcDetail, false, userDTO, now);
//			taskQcDetail.setExecutor(userDTO.getId());
			taskQcDetail.setTimes(0);
			// 需要判断是第几次质检
			BigDecimal conversionRate = rqcReLinesDTO.getConversionRate();
			BigDecimal pieceQty = rqcReLinesDTO.getPieceQty();

			if (null == conversionRate || conversionRate.compareTo(BigDecimal.ZERO) == 0) {
				taskQcDetail.setQty(pieceQty);
			} else {
				taskQcDetail.setQty(pieceQty.divide(conversionRate, 2, BigDecimal.ROUND_DOWN));
			}
			taskQcDetail.setDataVersion(0);
			String stockStatus = rqcReLinesDTO.getStockStatus();
			taskQcDetail.setResult(stockStatus);

			// 加入单据来源字段
			taskQcDetail.setRefType(2);
			taskQcDetail.setIsRechecked(1); // 来源复检
			taskQcDetail.setRefLineId(rqcReLinesDTO.getRqcReLineId());

			taskQcDetail.setIsSpotCheck(0); // 是否抽检
			taskQcDetail.setExecutor(null); // 无执行者

			this.mapper.save(taskQcDetail);
		}

		if (ObjectUtils.isNotNull(outHosted)) {
			// 代管出库操作
			String inType = "7"; // 入库类型-代管出库
			String status = "1"; // 库存状态-正常
			hostedHelper.rqcReLinesOutHosted(outHosted, inType, status, userDTO, now, warehouserId);
		}

		return true;
	}

	@Override
	public Page<TaskQcDetailDTO> findList(TaskQcDetailQueryVO taskQcDetailQueryVO) {
		// 代码实现
		String[] sorts = taskQcDetailQueryVO.getSorts().split(",");
		Criteria criteria = this.initCondition(true, sorts, TaskQcDetail.class);
		TaskQcDetailDTO taskQcDetailDTO = new TaskQcDetailDTO();
		BeanUtils.copyProperties(taskQcDetailQueryVO, taskQcDetailDTO);
		Restriction r = buildCondition(taskQcDetailDTO);
		// 任务条件 (余量>0 作废) 状态为可用,rcvHeaderId,若是双人质检,则执行者不能是当前的登录用户
//		Restriction and1 = Restrictions.and(Restrictions.gt("remainQty", 0), Restrictions.eq("status", "1"));
		Restriction and1 = Restrictions.eq("status", "1");
		Restriction eq1 = Restrictions.eq("itemHealthIsDouble", 1);
		Restriction eq2 = Restrictions.eq("itemHealthIsDouble", 0);
		Restriction ne = Restrictions.ne("executor", userUtils.getUserId());
		Restriction or1 = Restrictions.or(Restrictions.and(eq1, ne), eq2);
		Restriction condition = Restrictions.and(r, and1, or1);
		criteria.setRestriction(condition);

		this.startPage(taskQcDetailQueryVO);
		List<TaskQcDetail> list = this.mapper.findByCriteria(criteria);
		Page<TaskQcDetail> page = PageUtils.getPage(list);
		Page<TaskQcDetailDTO> page2 = this.buildPage(page, (p) -> {
			TaskQcDetailDTO target = new TaskQcDetailDTO();
			BeanUtils.copyProperties(p, target);
			return target;
		});
		return page2;
	}

	/**
	 * 普通条件分页
	 */
	@Override
	public Page<TaskQcDetailDTO> findList2(TaskQcDetailQueryVO taskQcDetailQueryVO) {
		// 条件查询2 走原生sql
		TaskQcDetailDTO taskQcDetailDTO = new TaskQcDetailDTO();
		BeanUtils.copyProperties(taskQcDetailQueryVO, taskQcDetailDTO);
		String userId = userUtils.getUserId();
		String enterpriseId = userUtils.getEnterpriseId();
		taskQcDetailDTO.setExecutor(userId);
		taskQcDetailDTO.setEnterpriseId(enterpriseId);
		this.startPage(taskQcDetailQueryVO);
		List<TaskQcDetailDTO> list = this.mapper.findList2(taskQcDetailDTO);
		return PageUtils.getPage(list);
	}

	/**
	 * 提取收货头表信息(原生sql)
	 */
	@Override
	public Page<RcvHDTO> extractRcvHWithNativeSql(RcvQueryVO rcvQueryVO, PageParam pageParam) {
		String enterpriseId = rcvQueryVO.getEnterpriseId();
		String excuteUser = rcvQueryVO.getExcuteUser();
		UserDTO userDTO = userUtils.getUserDTO();
		if (StringUtils.isBlank(excuteUser) || StringUtils.isBlank(enterpriseId)) {
			String enterpriseId2 = userDTO.getEnterpriseId();
			String userName = userDTO.getUsername();// 到底是用户id还是用户名得统一,建议用用户名 TODO
			rcvQueryVO.setEnterpriseId(enterpriseId2);
			rcvQueryVO.setExcuteUser(userName);
		}
		String mtlOwnerId = rcvQueryVO.getMtlOwnerId();
		if (StringUtils.isBlank(mtlOwnerId) && enableDefaultCargoOwnerSearch) {
			UserBizModel userBizModel = userDTO.getUserBizModel();
			Set<String> consignors = userBizModel.getConsignors();
			if (!ObjectUtils.isNull(consignors)) {
				List<String> list = new ArrayList<>(consignors);
				String cid = list.get(0);
				rcvQueryVO.setMtlOwnerId(cid);
			}
		}
		this.startPage(pageParam);
		List<RcvHDTO> list = this.mapper.extractRcvHWithNativeSql(rcvQueryVO);
		return PageUtils.getPage(list);
	}

	/**
	 * 提取收货头表信息(原生sql)
	 */
	@Override
	public Page<RcvHDTO> extractRcvHWithNativeSql1(RcvQueryVO rcvQueryVO, PageParam pageParam) {
		String enterpriseId = rcvQueryVO.getEnterpriseId();
		String excuteUser = rcvQueryVO.getExcuteUser();
		UserDTO userDTO = userUtils.getUserDTO();
		if (StringUtils.isBlank(excuteUser) || StringUtils.isBlank(enterpriseId)) {
			String enterpriseId2 = userDTO.getEnterpriseId();
			String userName = userDTO.getUsername();// 到底是用户id还是用户名得统一,建议用用户名 TODO
			rcvQueryVO.setEnterpriseId(enterpriseId2);
			rcvQueryVO.setExcuteUser(userName);
		}
		String mtlOwnerId = rcvQueryVO.getMtlOwnerId();
		if (StringUtils.isBlank(mtlOwnerId) && enableDefaultCargoOwnerSearch) {
			UserBizModel userBizModel = userDTO.getUserBizModel();
			Set<String> consignors = userBizModel.getConsignors();
			if (!ObjectUtils.isNull(consignors)) {
				List<String> list = new ArrayList<>(consignors);
				String cid = list.get(0);
				rcvQueryVO.setMtlOwnerId(cid);
			}
		}
		this.startPage(pageParam);
		List<RcvHDTO> list = this.mapper.extractRcvHWithNativeSql1(rcvQueryVO);
		return PageUtils.getPage(list);
	}

	/**
	 * 提取任务池任务
	 */
	@Override
	public Page<TaskQcDetailDTO> extractTaskWithNativeSql(TaskQcDetailQueryVO taskQcDetailQueryVO) {
//		String rcvHeaderId = taskQcDetailQueryVO.getRcvHeaderId();
//		AssertUtils.isNotBlank(rcvHeaderId, "头表id(rcvHeaderId)不可为空!");
		TaskQcDetailDTO taskQcDetailDTO = new TaskQcDetailDTO();
		BeanUtils.copyProperties(taskQcDetailQueryVO, taskQcDetailDTO);
		String userId = userUtils.getUserName();
		String enterpriseId = userUtils.getEnterpriseId();
		taskQcDetailDTO.setExecutor(userId);
		taskQcDetailDTO.setEnterpriseId(enterpriseId);
//		taskQcDetailDTO.setStatus("1"); // 查询状态为1的
		taskQcDetailQueryVO.setPageSize(500);
		taskQcDetailQueryVO.setPageNum(1);
		this.startPage(taskQcDetailQueryVO);
		List<TaskQcDetailDTO> list = this.mapper.findList(taskQcDetailDTO);
		if(list.size()==0){
			return new Page<>();
		}
		Set<String> itemIds = list.stream().map(x -> x.getItemId()).collect(Collectors.toSet());
		RestMessage<List<BaseMtlItemMst>> listByIds = itemRemoteCaller.getListByIds(itemIds);
		if(listByIds.getData()==null||!listByIds.isSuccess()){
			throw new BizException("商品信息查询失败");
		}
		List<BaseMtlItemMst> data = listByIds.getData();
		for (TaskQcDetailDTO dto : list) {
			//新增标识，是否从收货带过来的库别
			if(ToolKits.isNotEmpty(dto.getWhAreaCategoryCode())){
				dto.setCategoryCodeFromRcvFlag("1");
			}else {
				dto.setCategoryCodeFromRcvFlag("0");
			}

			dto.setConsignorId(dto.getMtlOwnerId());
			String rcvType = dto.getRcvType();
			if (StringUtils.isBlank(rcvType) && rcvType.equals(BizConstant.WAIT_CHECK_IN)) {
				String hostLocatorId = dto.getHostLocatorId();
				if (!StringUtils.isBlank(hostLocatorId)) {
					dto.setWhAreaCategoryCode(BizConstant.DGK);
				}
				// 取上一步代管验收结论
				List<RqcLinesDTO> hostRqcResult = rqcLinesMapper.getHostRqcResult(dto.getItemId(), dto.getBatchId());
				if (!ObjectUtils.isNull(hostRqcResult)) {
					RqcLinesDTO rqcLinesDTO = hostRqcResult.get(0);
					String stockStatus = rqcLinesDTO.getStockStatus();
					String handlingMeasure = rqcLinesDTO.getHandlingMeasure();
					String handlingReason = rqcLinesDTO.getHandlingReason();
					String defReasonExt = rqcLinesDTO.getDefReasonExt();
					String defReason = rqcLinesDTO.getDefReason();
					dto.setStockStatus(stockStatus);
					dto.setHandlingMeasure(handlingMeasure);
					dto.setHandlingReason(handlingReason);
					dto.setDefReason(defReason);
					dto.setDefReasonExt(defReasonExt);
				}
			}
			BaseMtlItemMst itemMst = data.stream().filter(x -> x.getItemId().equals(dto.getItemId())).findFirst().orElse(null);
			if(itemMst!=null){
				List<BaseMtlItemUomConversions> baseMtlItemUomConversionsList = itemMst.getBaseMtlItemUomConversionsList();
				if(baseMtlItemUomConversionsList.size()>0){
					BaseMtlItemUomConversions itemUomConversions = baseMtlItemUomConversionsList.get(0);
					dto.setLength(itemUomConversions.getLength());
					dto.setWidth(itemUomConversions.getWidth());
					dto.setHeight(itemUomConversions.getHeight());
				}
			}

		}
		try {
			supervisionCodeService.isSupervise(list, 0);// 是否监管
		} catch (Exception e) {
			log.error("扫描监管码", e);
		}
		return PageUtils.getPage(list);
	}

	private boolean canCommit(String taskRqcId, int row, String statusResult, TaskQcDetailDTO taskQcDetailDTO,
							  boolean splitFlag) {
		// 数据库乐观锁
		TaskQcDetail taskQcDetail = this.mapper.findById(taskRqcId, TaskQcDetail.class);
		AssertUtils.notNull(taskQcDetail, String.format("第[%d]行,质检任务id:[%s]查询的任务为空!", row, taskRqcId));
		String status = taskQcDetail.getStatus();
		if (!"1".equals(status))
			throw new BizException(String.format("第[%d]行,质检任务id:[%s]查询的任务已经执行完毕,请刷新重试!", row, taskRqcId));

		BigDecimal pieceQty2 = taskQcDetail.getPieceQty();
		BigDecimal pieceQty = taskQcDetailDTO.getPieceQty();
		if (splitFlag && pieceQty2.compareTo(pieceQty) < 1) {
			throw new BizException("第[%d]行,拆分的数量不可大于等于原数量!");
		}

		Criteria criteria = new Criteria(TaskQcDetail.class);
		Integer dataVersion = taskQcDetail.getDataVersion();

		// 这里只需要dataVersion其实就可以了
		criteria.setRestriction(
				Restrictions.and(Restrictions.eq("taskRqcId", taskRqcId), Restrictions.eq("dataVersion", dataVersion)));
		Map<String, Object> map = MapUtils.put("dataVersion", dataVersion + 1).getMap();
		if (!StringUtils.isBlank(statusResult)) {
			map.put("status", statusResult);
		}
		long count = this.mapper.updateMapByCriteria(map, criteria);
		if (0 >= count)
			return false;
		return true;
	}

	@Transactional
	@Override
	public Object splitTask(List<TaskQcDetailDTO> taskQcDetailDTOList) {
		// 任务拆分
		// 拆分加锁
		UserDTO userDTO = userUtils.getUserDTO();
		boolean editFlag = false;
		int row = 0;
		List<TaskQcDetail> list = new ArrayList<>();
		List<String> idlist = new ArrayList<>();
		Date now = new Date();
		for (TaskQcDetailDTO taskQcDetailDTO : taskQcDetailDTOList) {
			row++;
			BigDecimal pieceQty = taskQcDetailDTO.getPieceQty();
			if (pieceQty == null || pieceQty.compareTo(BigDecimal.ZERO) == 0) {
				throw new BizException(String.format("第[%d]行,拆分的数量不可为空,或者0", row));
			}
			String taskRqcId = taskQcDetailDTO.getTaskRqcId();
			if (ObjectUtils.isNotNull(taskRqcId)) {
				editFlag = true;
				// 加入乐观锁
				if (!canCommit(taskRqcId, row, null, taskQcDetailDTO, true))
					throw new BizException(
							String.format("第[%d行],质检任务拆分失败!taskRqcId为[%s]的任务处理中,请刷新重试!", row, taskRqcId));
			} else {
				editFlag = false;
			}
			String rcvLineId = taskQcDetailDTO.getRcvLineId();
			RcvLines findById = this.rcvLinesMapper.findById(rcvLineId, RcvLines.class);
			if (findById != null && findById.getPieceQty().compareTo(pieceQty) < 0) {
				throw new BizException(String.format("第[%d]行,拆分的数量不可大于等于收货数量", row));
			}

			TaskQcDetail taskQcDetail = new TaskQcDetail();
			BeanUtils.copyProperties(taskQcDetailDTO, taskQcDetail);
//			this.vaildateModel(taskQcDetail, editFlag, userDTO);
			this.buildField(taskQcDetail, editFlag, userDTO, now);
//			this.setBaseSysField(taskQcDetail, editFlag, userDTO, null);
			if (ObjectUtils.isNotNull(taskRqcId)) {
				// 更新
				taskQcDetail.setIsSpilt(1);
				taskQcDetail.setSpilterName(userDTO.getUsername());
				taskQcDetail.setSegment1("1"); // 使用预留字段保存拆分行标识，是否拆分标识  0 或者空未拆分  1 已拆分 是原单   2已拆分 拆分出来的新单据
				this.mapper.updateWithValidate(taskQcDetail,
						p -> ObjectUtils.isNotNull(p) && ObjectUtils.isNotNull(p.getValue()));
//				list.add(taskQcDetail);
				idlist.add(taskRqcId);

				//更新对应的rcv单据
				findById.setQty(taskQcDetail.getQty());
				findById.setPieceQty(taskQcDetail.getQty().multiply(taskQcDetail.getConversionRate()));
				findById.setOddCaseQty(taskQcDetail.getQty());
				this.rcvLinesMapper.update(findById);
			} else {
				// 新增
				taskQcDetail.setIsSpilt(0);
				taskQcDetail.setExecutor(null); // 无执行者
				taskQcDetail.setStatus("1"); // 可执行状态(为了防止copy的数据不是执行态)
				taskQcDetail.setSegment1("2"); // 使用预留字段保存拆分行标识  0未拆分  1 已拆分 是原单   2已拆分 拆分出来的新单据
				taskQcDetail.setManufacturerLotNum(findById.getManufacturerLotNum());//
				this.mapper.save(taskQcDetail);
//				list.add(taskQcDetail);
				idlist.add(taskQcDetail.getTaskRqcId());

				RcvLines rcvLinesNew = new RcvLines();
				BeanUtils.copyProperties(findById, rcvLinesNew);
				//从对应的rcv单据拆分出新的数据
				rcvLinesNew.setQty(taskQcDetail.getQty());
				rcvLinesNew.setPieceQty(taskQcDetail.getQty().multiply(taskQcDetail.getConversionRate()));
				rcvLinesNew.setOddCaseQty(taskQcDetail.getQty());
				this.rcvLinesMapper.save(rcvLinesNew);
				//同时保存附属表
				RcvLinesProfiles rcvLinesProfilesNew =new RcvLinesProfiles();
				RcvLinesProfiles rcvLinesProfiles = rcvLinesProfilesMapper.findById(rcvLineId,RcvLinesProfiles.class);
				BeanUtils.copyProperties(rcvLinesProfiles, rcvLinesProfilesNew);
				rcvLinesProfilesNew.setRcvLineId(rcvLinesNew.getRcvLineId());
				this.rcvLinesProfilesMapper.save(rcvLinesProfilesNew);

				//更新拆分出来的taskQcDetail中的rcvLineId
				taskQcDetail.setRcvLineId(rcvLinesNew.getRcvLineId());
				taskQcDetail.setRefLineId(rcvLinesNew.getRcvLineId());
				this.mapper.update(taskQcDetail);
			}

		}
//		List<TaskInstockDetailDTO> collect = Optional.ofNullable(list).orElse(Collections.emptyList()).stream()
//				.map(p -> {
//					TaskInstockDetailDTO target = new TaskInstockDetailDTO();
//					BeanUtils.copyProperties(p, target);
//					return target;
//				}).collect(Collectors.toList());
		return idlist;
	}

	@Transactional
	@Override
	public Object taskMerge(List<TaskQcDetailDTO> taskQcDetailDTOList) {
		AssertUtils.isNotEmpty(taskQcDetailDTOList, "合并的任务集合为空!");
		int size = taskQcDetailDTOList.size();
		if (size < 2) {
			throw new BizException("至少需要两个及以上的任务才可做合并操作!");
		}
		// 任务合并
		UserDTO userDTO = userUtils.getUserDTO();
		boolean editFlag = false;
		List<TaskQcDetail> list = new ArrayList<>();
		List<String> idlist = new ArrayList<>();
		int row = 1;
		Date now = new Date();
		// 合并后是否需要记录合并后的id,或者合并前的任务id集合
		TaskQcDetailDTO taskQcDetailDTO = taskQcDetailDTOList.get(0); // 以以第一行为基准

		// Step1: 是否可合并校验
		for (int i = 1; i < size; i++) {
			row++;
			TaskQcDetailDTO taskQcDetailDTO2 = taskQcDetailDTOList.get(i);
			boolean b = equal(taskQcDetailDTO2, taskQcDetailDTO);
			if (!b) {
				throw new BizException(String.format("第[%d]行,不是同品同批的商品,无法进行合并操作,请检查重试!", row));
			}
		}
		int row2 = 0;
		BigDecimal mergePieceQty = BigDecimal.ZERO;
		for (TaskQcDetailDTO taskDTO : taskQcDetailDTOList) {
			row2++;
			String taskRqcId = taskDTO.getTaskRqcId();
			editFlag = true;
			// 加入乐观锁
			if (!canCommit(taskRqcId, row, "0", taskDTO, false))
				throw new BizException(String.format("第[%d行],质检任务合并失败!taskRqcId为[%s]的任务处理中,请刷新重试!", row2, taskRqcId));
			BigDecimal pieceQty = taskDTO.getPieceQty();
			mergePieceQty.add(pieceQty);
		}

		// 重新生成新的任务
		// 计算整件,零散
		TaskQcDetail taskQcDetail = new TaskQcDetail();
		BeanUtils.copyProperties(taskQcDetailDTO, taskQcDetail);
		this.buildDefaultField(taskQcDetail, false, userDTO, now);
		this.buildField(taskQcDetail, false, userDTO, now);
		BigDecimal conversionRate = taskQcDetail.getConversionRate();
		if (conversionRate == null) {
			conversionRate = BigDecimal.ONE;
		}
		taskQcDetail.setConversionRate(conversionRate);
		taskQcDetail.setQty(mergePieceQty.divide(conversionRate, 2, RoundingMode.DOWN));
		taskQcDetail.setTaskRqcId(String.valueOf(SnowFlakeUtils.getId()));
		taskQcDetail.setExecutor(null);
		this.mapper.save(taskQcDetail);
		return true;
	}

	private boolean equal(TaskQcDetailDTO taskQcDetailDTO2, TaskQcDetailDTO taskQcDetailDTO) {
		String itemId = taskQcDetailDTO.getItemId();
		String batchId = taskQcDetailDTO.getBatchId();
		int hashCode = itemId.concat(batchId).hashCode();

		String itemId2 = taskQcDetailDTO2.getItemId();
		String batchId2 = taskQcDetailDTO2.getBatchId();
		int hashCode2 = itemId2.concat(batchId2).hashCode();
		if (hashCode == hashCode2) {
			return true;
		}
		return false;
	}

	public void updateTaskToFinshed(List<RcvLinesDTO> rcvLinesDTO) {
		List<String> list = rcvLinesDTO.stream().map(RcvLinesDTO::getRcvLineId).collect(Collectors.toList());
		this.mapper.updateTaskToFinshed(list);
	}

	@Override
	public Page<RcvHDTO> extractRcvHWithNativeSqlNew(RcvQueryVO rcvQueryVO, PageParam pageParam) {
		String enterpriseId = rcvQueryVO.getEnterpriseId();
		String excuteUser = rcvQueryVO.getExcuteUser();
		UserDTO userDTO = userUtils.getUserDTO();
		if (StringUtils.isBlank(excuteUser) || StringUtils.isBlank(enterpriseId)) {
			String enterpriseId2 = userDTO.getEnterpriseId();
			String userName = userDTO.getUsername();// 到底是用户id还是用户名得统一,建议用用户名 TODO
			rcvQueryVO.setEnterpriseId(enterpriseId2);
			rcvQueryVO.setExcuteUser(userName);
		}
		String mtlOwnerId = rcvQueryVO.getMtlOwnerId();
		if (StringUtils.isBlank(mtlOwnerId) && enableDefaultCargoOwnerSearch) {
			UserBizModel userBizModel = userDTO.getUserBizModel();
			Set<String> consignors = userBizModel.getConsignors();
			if (!ObjectUtils.isNull(consignors)) {
				List<String> list = new ArrayList<>(consignors);
				String cid = list.get(0);
				rcvQueryVO.setMtlOwnerId(cid);
			}
		}
		this.startPage(pageParam);
		List<RcvHDTO> list = this.mapper.extractRcvHWithNativeSqlNew(rcvQueryVO);
		for(RcvHDTO rcvHDTO : list){
			List<String> distCodes= Lists.newArrayList();
			distCodes.add("oms_asn_bill_type");
			List<Map<String,String>> distInfos =taskQcDetailMapper.queryDictInfo(distCodes);
			if(distInfos!=null && distInfos.size()>0){
				List<Map<String,String>> billTypeList=distInfos.stream().filter(dist-> Objects.equals(dist.get("type_code"),"oms_asn_bill_type")).collect(Collectors.toList());
				for(Map<String,String> map : billTypeList){
					if(Objects.equals(map.get("dict_code"),rcvHDTO.getRcvType())){
						rcvHDTO.setRcvTypeName(map.get("dict_name"));
						break;
					}
				}
			}
			if(rcvHDTO.getRcvDate()!=null){
				rcvHDTO.setRcvDateStr(DateUtils.format(rcvHDTO.getRcvDate(), DatePattern.NORM_DATE_PATTERN));
			}
		}
		return PageUtils.getPage(list);
	}

	/**
	 * 提取任务池任务
	 */
	@Override
	public Page<TaskQcDetailDTO> extractTaskWithNativeSqlNew(TaskQcDetailQueryVO taskQcDetailQueryVO) {
		TaskQcDetailDTO taskQcDetailDTO = new TaskQcDetailDTO();
		BeanUtils.copyProperties(taskQcDetailQueryVO, taskQcDetailDTO);
		String userId = userUtils.getUserName();
		String enterpriseId = userUtils.getEnterpriseId();
		taskQcDetailDTO.setExecutor(userId);
		taskQcDetailDTO.setEnterpriseId(enterpriseId);
//		taskQcDetailDTO.setStatus("1"); // 查询状态为1的
		taskQcDetailQueryVO.setPageSize(500);
		taskQcDetailQueryVO.setPageNum(1);
		this.startPage(taskQcDetailQueryVO);
		List<TaskQcDetailDTO> list = this.mapper.findListNew(taskQcDetailDTO);
//		for (TaskQcDetailDTO dto : list) {
//			dto.setConsignorId(dto.getMtlOwnerId());
//			if (dto.getItemHealthIsDouble() != null && dto.getItemHealthIsDouble() == 1 && dto.getRefType() != null
//					&& dto.getRefType() != 2) {// 双人验收时，复检后质检时才扫描监管码
//				dto.setIsSupervise(0);
//			} else {
//				dto.setIsSupervise(null);
//			}
//			String rcvType = dto.getRcvType();
//			if (StringUtils.isBlank(rcvType) && rcvType.equals(BizConstant.WAIT_CHECK_IN)) {
//				String hostLocatorId = dto.getHostLocatorId();
//				if (!StringUtils.isBlank(hostLocatorId)) {
//					dto.setWhAreaCategoryCode(BizConstant.DGK);
//				}
//				// 取上一步代管验收结论
//				List<RqcLinesDTO> hostRqcResult = rqcLinesMapper.getHostRqcResult(dto.getItemId(), dto.getBatchId());
//				if (!ObjectUtils.isNull(hostRqcResult)) {
//					RqcLinesDTO rqcLinesDTO = hostRqcResult.get(0);
//					String stockStatus = rqcLinesDTO.getStockStatus();
//					String handlingMeasure = rqcLinesDTO.getHandlingMeasure();
//					String handlingReason = rqcLinesDTO.getHandlingReason();
//					String defReasonExt = rqcLinesDTO.getDefReasonExt();
//					String defReason = rqcLinesDTO.getDefReason();
//					dto.setStockStatus(stockStatus);
//					dto.setHandlingMeasure(handlingMeasure);
//					dto.setHandlingReason(handlingReason);
//					dto.setDefReason(defReason);
//					dto.setDefReasonExt(defReasonExt);
//				}
//			}
//		}
//		try {
//			supervisionCodeService.isSupervise(list, 0);// 是否监管
//		} catch (Exception e) {
//			log.error("扫描监管码", e);
//		}
		return PageUtils.getPage(list);
	}

}
