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

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.type.TypeReference;
import com.github.pagehelper.util.StringUtil;
import com.prolog.common.util.DateUtils;
import com.prolog.common.util.ToolKits;
import com.prolog.cs.basic.chain.model.cargo.BaseCargoOwnerMst;
import com.prolog.cs.basic.chain.model.customer.BaseCustomerMst;
import com.prolog.cs.basic.chain.model.customer.vo.BaseCustomerMstRequestVO;
import com.prolog.cs.basic.chain.model.supplier.BaseSupplierMst;
import com.prolog.cs.basic.common.model.SysRegistry;
import com.prolog.cs.basic.item.model.BaseMtlItemMst;
import com.prolog.cs.basic.item.model.BaseMtlItemUomConversions;
import com.prolog.cs.basic.warehouse.model.BaseWmsWarehouseMst;
import com.prolog.cs.biz.inbound.dao.OmsAsnBillDMapper;
import com.prolog.cs.biz.inbound.dao.OmsAsnBillHMapper;
import com.prolog.cs.biz.inbound.dao.SupervisionCodeMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvHeadersMapper;
import com.prolog.cs.biz.inbound.dao.rcv.RcvLinesMapper;
import com.prolog.cs.biz.inbound.dao.task.TaskQcDetailMapper;
import com.prolog.cs.biz.inbound.dto.IsSuperviseDTO;
import com.prolog.cs.biz.inbound.dto.Supervise4CargoChange;
import com.prolog.cs.biz.inbound.dto.Supervise4CargoChangeDetail;
import com.prolog.cs.biz.inbound.dto.SuperviseResultDTO;
import com.prolog.cs.biz.inbound.dto.rcv.RcvHDTO;
import com.prolog.cs.biz.inbound.model.OmsAsnBillD;
import com.prolog.cs.biz.inbound.model.OmsAsnBillH;
import com.prolog.cs.biz.inbound.model.SupervisionCode;
import com.prolog.cs.biz.inbound.model.task.TaskQcDetail;
import com.prolog.cs.biz.inbound.remote.BaseItemRemoteCaller;
import com.prolog.cs.biz.inbound.remote.BaseWmsWarehouseCaller;
import com.prolog.cs.biz.inbound.remote.ChainRemoteCaller;
import com.prolog.cs.biz.inbound.remote.CommonCaller;
import com.prolog.cs.biz.inbound.service.SupervisionCodeService;
import com.prolog.cs.biz.inbound.vo.SupervisionCodeVO;
import com.prolog.cs.data.exchange.client.ExchangeSender;
import com.prolog.cs.data.exchange.client.core.EtlMessage;
import com.prolog.cs.data.exchange.client.core.EtlTypeConstants;
import com.prolog.framework.authority.core.dto.UserDTO;
import com.prolog.framework.authority.user.UserTemplate;
import com.prolog.framework.beans.BeanUtils;
import com.prolog.framework.bz.common.search.SearchApi;
import com.prolog.framework.bz.core.util.ObjectUtils;
import com.prolog.framework.common.message.RestMessage;
import com.prolog.framework.core.exception.BizException;
import com.prolog.framework.core.exception.NullParameterException;
import com.prolog.framework.core.pojo.Page;
import com.prolog.framework.core.restriction.*;
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 org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Service
public class SupervisionCodeServiceImpl implements SupervisionCodeService {

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

//	@Value("${prolog.taobao.serverUrl}")
//	private String serverUrl;
//
//	@Value("${prolog.taobao.appKey}")
//	private String appKey;
//
//	@Value("${prolog.taobao.appSecret}")
//	private String appSecret;
//
//	@Value("${prolog.taobao.refEntId}")
//	private String refEntId;

	@Resource
	private SupervisionCodeMapper mapper;

	@Resource
	private BaseItemRemoteCaller baseItemRemoteCaller;

	@Resource
	private ChainRemoteCaller chainRemoteCaller;

	@Resource
	private RcvLinesMapper rcvLinesMapper;

	@Resource
	private RcvHeadersMapper rcvHeadersMapper;

	@Resource
	private TaskQcDetailMapper taskQcDetailMapper;
	@Resource
	private OmsAsnBillHMapper OmsAsnBillHMapper;

	@Resource
	private BaseWmsWarehouseCaller baseWmsWarehouseCaller;

	@Resource
	private ChainRemoteCaller chainClient;

	@Resource
	private ExchangeSender exchangeSender;

	@Resource
	private UserTemplate userTemplate;

	@Resource
	private SearchApi searchApi;

	@Resource
	private RedisTemplate redisTemplate;

	@Resource
	private OmsAsnBillDMapper omsAsnBillDMapper;

	@Resource
	private CommonCaller commonCaller;

	@Override
	public SuperviseResultDTO addSupervisionCode(SupervisionCode dto){
		log.info("addSupervisionCode,dto="+JSON.toJSONString(dto));
		AssertUtils.notNull(dto, "入参不能为空");
		String refBillId = dto.getRefBillId();
		AssertUtils.notNull(refBillId, "单据Id不能为空");
		Integer stage = dto.getStage();
		AssertUtils.notNull(stage, "入参stage不能为空");
		if(queryIsUnlock(refBillId)){//已经解锁
			return null;
		}
		if(dto.getUnlock()!=null && dto.getUnlock()==1){
			spellCommonSupervisionCode(dto);
			mapper.save(dto);
			return null;
		}
		dto.setUploadFlag("0");
		dto.setDownFlag(0);
		dto.setSaveType(1);//默认为入库，如果来源是出库，则类型为出库
		if(ToolKits.isNotEmpty(dto.getSource()) && "out".equals(dto.getSource())){
			dto.setSaveType(2);
		}
		dto.setUnlock(0);
		String supervisionCode = dto.getSupervisionCode();
		AssertUtils.notNull(supervisionCode, "追溯码不能为空");
		String refBillLineId = dto.getRefBillLineId();
		AssertUtils.notNull(refBillLineId, "单据明细Id不能为空");
		String packLevel = dto.getPackLevel();
		if(StringUtils.isBlank(dto.getPackSize()) && !StringUtils.isBlank(packLevel)){
			if("0".equals(packLevel))
				dto.setPackSize(dto.getMaxSu());
			if("1".equals(packLevel))
				dto.setPackSize(dto.getMiddleSu());
			if("2".equals(packLevel))
				dto.setPackSize(dto.getMinSu());
		}
		//PDA扫码数根据整散判断，目前没有根据包装规格
		//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
		String warehouseId = dto.getWarehouseId();
		if (stage !=5 && stage!=50 && stage!=51 && stage!=52 &&stage!=6 && stage!=7 && StringUtils.isBlank(dto.getPackSize())){
			throw new BizException("接口包装数必传");
		}

		SuperviseResultDTO tempSuperviseResultDTO=itemsByBill1(refBillId, refBillLineId);
		if(tempSuperviseResultDTO!=null && tempSuperviseResultDTO.isComplete()!=null && tempSuperviseResultDTO.isComplete()){
			return tempSuperviseResultDTO;
		}
		if(StringUtil.isEmpty(dto.getWarehouseCode())){
			BaseWmsWarehouseMst baseWmsWarehouseMst = getWarehouse(warehouseId);
			if(baseWmsWarehouseMst!=null){
				dto.setWarehouseCode(baseWmsWarehouseMst.getWarehouseCode());
			}
		}
		spellCommonSupervisionCode(dto);
		if(stage==0){
			buildSupervisionCodeInbound(dto);
		}else{
			//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
			if(StringUtil.isEmpty(dto.getShipperCode())){
				if(dto.getBillType()==null||"2".equals(dto.getBillType())||"1".equals(dto.getBillType())||"5".equals(dto.getBillType())||"6".equals(dto.getBillType())){
					BaseCustomerMst shipper = getShipper(dto.getShipperId());
					if(shipper!=null){
						dto.setCargoOwnerId(shipper.getCargoOwnerId());
						dto.setCargoOwnerCode(shipper.getCargoOwnerId());
						dto.setShipperCode(shipper.getCustomerCode());
						dto.setCompanyCode(shipper.getCustomerCode());
						dto.setShipperId(shipper.getCustomerId());
					}
				}else{
					BaseSupplierMst supplier = getSupplierById(dto.getSupplierId());
					if(supplier!=null){
						dto.setCargoOwnerId(supplier.getCargoOwnerId());
						dto.setCargoOwnerCode(supplier.getCargoOwnerCode());
						dto.setSupplierCode(supplier.getSupplierCode());
						dto.setCompanyCode(supplier.getSupplierCode());
						dto.setSupplierId(supplier.getSupplierId());
					}
				}
			}
		}
		if(supervisionCode.split("\n").length > 1){
			String[] arr= supervisionCode.split("\n");
			Set<String> set = new HashSet(Arrays.asList(arr));
			for (String code : set) {
				try {
					if(StringUtils.isBlank(code)){
						continue;
					}
					dto.setSupervisionCode(code);

					if(!hasCacheKey(refBillId,refBillLineId,code)){
						addSupervisionCode(dto);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			return itemsByBill1(refBillId, refBillLineId);
		} else {
			String[] arr= supervisionCode.split("\n");
			if (arr.length>0) {
				dto.setSupervisionCode(arr[0]);
			}
		}
		if(!hasCacheKey(warehouseId,dto.getSrcCode(),dto.getSupervisionCode())){
			addSupervisionCodeCore(dto);
		}
		return itemsByBill1(refBillId, refBillLineId);
	}

	@Override
	@Transactional
	public SuperviseResultDTO addSupervisionCodes(List<SupervisionCode> dtos){
		if(dtos.size()==0){
			AssertUtils.notNull(dtos, "入参不能为空");
		}
		for(SupervisionCode dto:dtos){
			String refBillId = dto.getRefBillId();
			Integer stage = dto.getStage();
			if(queryIsUnlock(refBillId)){//已经解锁
				return null;
			}
			if(dto.getUnlock()!=null && dto.getUnlock()==1){
				spellCommonSupervisionCode(dto);
				mapper.save(dto);
				return null;
			}
			dto.setUnlock(0);
			String supervisionCode = dto.getSupervisionCode();
			AssertUtils.notNull(supervisionCode, "追溯码不能为空");
			AssertUtils.notNull(dto.getRefBillLineId(), "单据明细Id不能为空");
			String packLevel = dto.getPackLevel();
			if(StringUtils.isBlank(dto.getPackSize()) && !StringUtils.isBlank(packLevel)){
				if("0".equals(packLevel))
					dto.setPackSize(dto.getMaxSu());
				if("1".equals(packLevel))
					dto.setPackSize(dto.getMiddleSu());
				if("2".equals(packLevel))
					dto.setPackSize(dto.getMinSu());
			}
			//PDA扫码数根据整散判断，目前没有根据包装规格
			//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
			if( stage!=50 && stage!=51 && stage!=52 &&stage!=6 && stage!=7 && StringUtils.isBlank(dto.getPackSize())){
				throw new BizException("接口包装数必传");
			}

			SuperviseResultDTO tempSuperviseResultDTO=itemsByBill(refBillId,dto.getRefBillLineId());
			if(tempSuperviseResultDTO!=null && tempSuperviseResultDTO.isComplete()!=null && tempSuperviseResultDTO.isComplete()){
				return tempSuperviseResultDTO;
			}
			if(StringUtil.isEmpty(dto.getWarehouseCode())){
				BaseWmsWarehouseMst baseWmsWarehouseMst = getWarehouse(dto.getWarehouseId());
				if(baseWmsWarehouseMst!=null){
					dto.setWarehouseCode(baseWmsWarehouseMst.getWarehouseCode());
				}
			}
			spellCommonSupervisionCode(dto);
			if(stage==0){
				buildSupervisionCodeInbound(dto);
			}else{
				//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
				if(StringUtil.isEmpty(dto.getShipperCode())){
					if(dto.getBillType()==null||"2".equals(dto.getBillType())||"1".equals(dto.getBillType())||"5".equals(dto.getBillType())||"6".equals(dto.getBillType())){
						BaseCustomerMst shipper = getShipper(dto.getShipperId());
						if(shipper!=null){
							dto.setCargoOwnerId(shipper.getCargoOwnerId());
							dto.setCargoOwnerCode(shipper.getCargoOwnerId());
							dto.setShipperCode(shipper.getCustomerCode());
							dto.setCompanyCode(shipper.getCustomerCode());
							dto.setShipperId(shipper.getCustomerId());
						}
					}else{
						BaseSupplierMst supplier = getSupplierById(dto.getSupplierId());
						if(supplier!=null){
							dto.setCargoOwnerId(supplier.getCargoOwnerId());
							dto.setCargoOwnerCode(supplier.getCargoOwnerCode());
							dto.setSupplierCode(supplier.getSupplierCode());
							dto.setCompanyCode(supplier.getSupplierCode());
							dto.setSupplierId(supplier.getSupplierId());
						}
					}
				}
			}
			addSupervisionCodeCore(dto);
		}
		return null;
	}

	@Override
	@Transactional
	public SuperviseResultDTO addSupervisionCodeList(List<SupervisionCode> dtos) {
		if (dtos.size() == 0) {
			AssertUtils.notNull(dtos, "入参不能为空");
		}
		String refBillId = "";
		String refBillLineId = "";
		for (SupervisionCode dto : dtos) {
			refBillId = dto.getRefBillId();
			refBillLineId = dto.getRefBillLineId();
			Integer stage = dto.getStage();
			if (queryIsUnlock(refBillId)) {//已经解锁
				return null;
			}
			if (dto.getUnlock() != null && dto.getUnlock() == 1) {
				spellCommonSupervisionCode(dto);
				mapper.save(dto);
				return null;
			}
			dto.setUnlock(0);
			String supervisionCode = dto.getSupervisionCode();
			AssertUtils.notNull(supervisionCode, "追溯码不能为空");
			AssertUtils.notNull(dto.getRefBillLineId(), "单据明细Id不能为空");
			String packLevel = dto.getPackLevel();
			if (StringUtils.isBlank(dto.getPackSize()) && !StringUtils.isBlank(packLevel)) {
				if ("0".equals(packLevel))
					dto.setPackSize(dto.getMaxSu());
				if ("1".equals(packLevel))
					dto.setPackSize(dto.getMiddleSu());
				if ("2".equals(packLevel))
					dto.setPackSize(dto.getMinSu());
			}
			//PDA扫码数根据整散判断，目前没有根据包装规格
			//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
			if (stage != 50 && stage != 51 && stage != 52 && stage != 6 && stage != 7 && StringUtils.isBlank(dto.getPackSize())) {
				throw new BizException("接口包装数必传");
			}

			SuperviseResultDTO tempSuperviseResultDTO = itemsByBill1(refBillId, dto.getRefBillLineId());
			if (tempSuperviseResultDTO != null && tempSuperviseResultDTO.isComplete() != null && tempSuperviseResultDTO.isComplete()) {
				return tempSuperviseResultDTO;
			}
			if (StringUtil.isEmpty(dto.getWarehouseCode())) {
				BaseWmsWarehouseMst baseWmsWarehouseMst = getWarehouse(dto.getWarehouseId());
				if (baseWmsWarehouseMst != null) {
					dto.setWarehouseCode(baseWmsWarehouseMst.getWarehouseCode());
				}
			}
			spellCommonSupervisionCode(dto);
			if (stage == 0) {
				buildSupervisionCodeInbound(dto);
			} else {
				//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
				if (StringUtil.isEmpty(dto.getShipperCode())) {
					if (dto.getBillType() == null || "2".equals(dto.getBillType()) || "1".equals(dto.getBillType()) || "5".equals(dto.getBillType()) || "6".equals(dto.getBillType())) {
						BaseCustomerMst shipper = getShipper(dto.getShipperId());
						if (shipper != null) {
							dto.setCargoOwnerId(shipper.getCargoOwnerId());
							dto.setCargoOwnerCode(shipper.getCargoOwnerId());
							dto.setShipperCode(shipper.getCustomerCode());
							dto.setCompanyCode(shipper.getCustomerCode());
							dto.setShipperId(shipper.getCustomerId());
						}
					} else {
						BaseSupplierMst supplier = getSupplierById(dto.getSupplierId());
						if (supplier != null) {
							dto.setCargoOwnerId(supplier.getCargoOwnerId());
							dto.setCargoOwnerCode(supplier.getCargoOwnerCode());
							dto.setSupplierCode(supplier.getSupplierCode());
							dto.setCompanyCode(supplier.getSupplierCode());
							dto.setSupplierId(supplier.getSupplierId());
						}
					}
				}
			}
		}
		addSupervisionCodeCores(dtos);
		return itemsByBill1(refBillId, refBillLineId);
	}

	public void addSupervisionCodeCores(List<SupervisionCode> dtos) {
		List<SupervisionCode> saveList = new ArrayList<>();
		for (SupervisionCode dto : dtos) {
			String consignorId =StringUtils.isBlank(dto.getCargoOwnerId())? dto.getConsignorId():dto.getCargoOwnerId();
			BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(consignorId);
			if(baseCargoOwnerMst==null){
				throw new BizException("货主不能为空");
			}
			if(StringUtils.isBlank(dto.getItemCode())){
				String[] itemIds = {dto.getItemId()};
				RestMessage<List<BaseMtlItemMst>> itemResult = baseItemRemoteCaller.getListByIds(new HashSet<>(Arrays.asList(itemIds)));
				if (itemResult==null || !itemResult.isSuccess() || itemResult.getData() == null || itemResult.getData().size() == 0) {
					throw new BizException("商品不能为空");
				}
				List<BaseMtlItemMst> itemList=itemResult.getData();
				if(itemList.size()>0){
					dto.setItemCode(itemList.get(0).getItemCode());
				}
			}
			dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
			if(baseCargoOwnerMst != null) {
				Integer isCodeSecurePlat = baseCargoOwnerMst.getIsCodeSecurePlat();
				String enterpriseId = baseCargoOwnerMst.getEnterpriseId();
				if (isCodeSecurePlat !=null && isCodeSecurePlat == 2) {
					//查询系统配置的参数
					RestMessage<SysRegistry> restMessage = commonCaller.getRegistryInfo("refEntId",enterpriseId);
					if (!restMessage.isSuccess()) {
						throw new RuntimeException("未查询到 refEntId 的系统配置参数:" + restMessage.getMessage());
					}
					SysRegistry data1 = restMessage.getData();
					String refEntId = data1.getRegValue();

					RestMessage<SysRegistry> restMessage3 = commonCaller.getRegistryInfo("serverUrl",enterpriseId);
					if (!restMessage3.isSuccess()) {
						throw new RuntimeException("未查询到 serverUrl 的系统配置参数:" + restMessage.getMessage());
					}
					SysRegistry data3 = restMessage3.getData();
					String serverUrl = data3.getRegValue();

					RestMessage<SysRegistry> restMessage4 = commonCaller.getRegistryInfo("appKey",enterpriseId);
					if (!restMessage4.isSuccess()) {
						throw new RuntimeException("未查询到 appKey 的系统配置参数:" + restMessage.getMessage());
					}
					SysRegistry data4 = restMessage4.getData();
					String appKey = data4.getRegValue();

					RestMessage<SysRegistry> restMessage5 = commonCaller.getRegistryInfo("appSecret",enterpriseId);
					if (!restMessage5.isSuccess()) {
						throw new RuntimeException("未查询到 appSecret 的系统配置参数:" + restMessage.getMessage());
					}
					SysRegistry data5 = restMessage5.getData();
					String appSecret = data5.getRegValue();
//					TaobaoClient client = new DefaultTaobaoClient(serverUrl, appKey, appSecret);
//					//查询追溯码对应的药品信息
//					AlibabaAlihealthDrugCodeKytQuerycodeRequest req = new AlibabaAlihealthDrugCodeKytQuerycodeRequest();
//					req.setCodes(dto.getSupervisionCode());//999枇杷膏
//					req.setRefEntId(refEntId);//企业唯一标识
//					try {
//						TaobaoResponse rsp = client.execute(req);
//						ObjectMapper mapper = new ObjectMapper();
//						JsonNode node = mapper.readTree(rsp.getBody());
//						String code_status = node.get("alibaba_alihealth_drug_code_kyt_querycode_response").get("result")
//								.get("models").get("code_full_info_dto").get(0).get("code_status_type_d_t_o").get("code_status").asText();
//						if ("E".equals(code_status)) {//code_status I核注O核销A激活C注销E错误码
//							throw new BizException("码上放心平台返回结果：错误码");
//						}
//						JsonNode produce_info_dto = node.get("alibaba_alihealth_drug_code_kyt_querycode_response").get("result")
//								.get("models").get("code_full_info_dto").get(0).get("code_produce_info_d_t_o").get("produce_info_list")
//								.get("produce_info_dto").get(0);
//						String batch_no = produce_info_dto.get("batch_no").asText();
//						String expire_date = produce_info_dto.get("expire_date").asText();
//						String produce_date_str = produce_info_dto.get("produce_date_str").asText();
//						if (!batch_no.equals(dto.getManufacturerLotNum())) {
//							throw new BizException("收货批号【" + dto.getManufacturerLotNum() + "】跟码上放心平台批号【" + batch_no + "】不一致");
//						}
//					} catch (ApiException e) {
//						log.error("调用码上放心平台异常", e);
//						//throw new BizException("调用码上放心平台异常，请联系管理员");
//					} catch (BizException e) {
//						log.error("调用码上放心平台异常", e);
//						//throw new BizException(e.getMessage());
//					} catch (Exception e) {
//						log.error("调用码上放心平台异常", e);
//						//throw new BizException("系统异常");
//					}
				}
			}
			log.info("保存的监管码为：{}", dto.getSupervisionCode());
			saveList.add(dto);
		}
		if(saveList.size()>0){
			mapper.saveBatch(saveList);
		}

	}

	@Override
	public void delSupervisionCode(List<SupervisionCode> list) {
		String[] ids = list.stream().map(x -> x.getId()).toArray(String[]::new);
		mapper.deleteByIds(ids,SupervisionCode.class);
	}

	@Override
	public void deleteSupervisionCode(String Id) {
		SupervisionCode code = mapper.findById(Id, SupervisionCode.class);
		if(ToolKits.isEmpty(code)){
			throw new BizException("根据ID未查询到对应的数据，请刷新界面重试");
		}
		if(ToolKits.isNotEmpty(code.getUploadFlag()) && code.getUploadFlag().equals("1")){
			throw new BizException("该条数据"+code.getSupervisionCode()+"已经上传监管码平台，无法删除");
		}
		mapper.deleteById(Id,SupervisionCode.class);
	}

	private boolean hasCacheKey(String warehouseId,String srcCode,String supervisionCode) {
		String checkOnlyOne="wms:scanCode:"+warehouseId+"_"+srcCode+"_"+supervisionCode;
		Object s=redisTemplate.opsForValue().get(checkOnlyOne);
		if(!ObjectUtils.isNull(s)){
			return true;
		}
		return false;
	}

	private void spellCommonSupervisionCode(SupervisionCode dto) {
		UserDTO userDTO = userTemplate.getUserDTO();
		String userId = userDTO.getId();
		String userName = userDTO.getNickname();
		String enterpriseId = userDTO.getEnterpriseId();
		dto.setEnterpriseId(enterpriseId);
		Date date = new Date();
		dto.setCreator(userId);
		dto.setCreatorName(userName);
		dto.setGmtCreate(date);
		dto.setModifier(userId);
		dto.setModifierName(userName);
		dto.setGmtModified(date);
		dto.setStatus("10");
		dto.setUploadFlag("0");
		dto.setDownFlag(0);
		dto.setSaveType(1);//默认为入库，如果来源是出库，则类型为出库
		if(!ToolKits.isNotEmpty(dto.getSource()) && "out".equals(dto.getSource())){
			dto.setSaveType(2);
		}
		if(StringUtils.isEmpty(dto.getCodeType())){
			dto.setCodeType("1");//【11.TIAOM_TYPE】条码类型（1:监管码  2：防串码  3：唯一码）【条码类型，TIAOM_TYPE】
		}
		dto.setScanName(userName);
		dto.setScanDate(date);
		if (null != dto.getBillType()) {
			if (dto.getBillType().equals("1")) {
				dto.setSupervisionType(2);
			} else if (dto.getBillType().equals("2")) {
				dto.setSupervisionType(3);
			} else if (dto.getBillType().equals("5")) {
				dto.setSupervisionType(5);
			} else if (dto.getBillType().equals("6")) {
				dto.setSupervisionType(6);
			} else if (dto.getBillType().equals("7")) {
				dto.setSupervisionType(7);
			} else if (dto.getBillType().equals("8")) {
				dto.setSupervisionType(8);
			} else if (dto.getBillType().equals("9")) {
				dto.setSupervisionType(9);
			}
		}else{
			dto.setSupervisionType(3);
		}
	}

	/*private void buildSupervisionCodeInbound(SupervisionCode dto){
		RcvHDTO rcvDTO=rcvHeadersMapper.findByPkId(dto.getRefBillId());
		if (null!=rcvDTO && null!=rcvDTO.getAsnBillNum()) {
			dto.setSrcCode(rcvDTO.getAsnBillNum());
		}
		TaskQcDetail qcDetail = taskQcDetailMapper.findById(dto.getRefBillLineId(),TaskQcDetail.class);
		RcvLinesDTO rcvLinesDTO = null;
		if(qcDetail!=null){
			rcvLinesDTO=rcvLinesMapper.findByPkId(qcDetail.getRcvLineId());
		}else{
			rcvLinesDTO=rcvLinesMapper.findByPkId(dto.getRefBillLineId());
		}
		if(rcvLinesDTO!=null){
			dto.setItemCode(rcvLinesDTO.getItemNum());
			dto.setProductionDate(rcvLinesDTO.getBatchProductionDate());
			dto.setExpiredDate(rcvLinesDTO.getBatchExpiredDate());
			if(StringUtil.isEmpty(dto.getSupplierCode())){
				OmsAsnBillH OmsAsnBillH=OmsAsnBillHMapper.findById(rcvDTO.getAsnHeaderId(), OmsAsnBillH.class);
				if(!"2".equals(rcvDTO.getRcvType())){
					BaseSupplierMst supplier = getSupplierById(OmsAsnBillH.getShipperid());
					if(supplier!=null){
						dto.setCargoOwnerId(rcvDTO.getMtlOwnerId());
						dto.setCargoOwnerCode(rcvDTO.getMtlOwnerNum());
						dto.setSupplierCode(supplier.getSupplierCode());
						dto.setCompanyCode(supplier.getSupplierCode());
						dto.setSupplierId(supplier.getSupplierId());
					}
				}else{
					BaseCustomerMst shipper = getShipper(OmsAsnBillH.getShipperid());
					if(shipper!=null){
						dto.setCargoOwnerId(rcvDTO.getMtlOwnerId());
						dto.setCargoOwnerCode(rcvDTO.getMtlOwnerNum());
						dto.setShipperCode(shipper.getCustomerCode());
						dto.setCompanyCode(shipper.getCustomerCode());
						dto.setShipperId(shipper.getCustomerId());
					}
				}
			}
			if(StringUtil.isEmpty(dto.getCargoOwnerCode()) && !StringUtil.isEmpty(rcvDTO.getMtlOwnerId())){//货主必填，to do
				BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(rcvDTO.getMtlOwnerId());
				dto.setCargoOwnerId(baseCargoOwnerMst.getCargoOwnerId());
				dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
			}
			if("2".equals(rcvDTO.getRcvType())){
				dto.setSupervisionType(1);
			}else{
				dto.setSupervisionType(0);
			}
		}
	}*/

	private void buildSupervisionCodeInbound(SupervisionCode dto){
		TaskQcDetail qcDetail = taskQcDetailMapper.findById(dto.getRefBillLineId(),TaskQcDetail.class);
		OmsAsnBillD omsAsnBillD = null;
		if (qcDetail != null) {
			omsAsnBillD = omsAsnBillDMapper.findById(qcDetail.getRcvLineId(), OmsAsnBillD.class);
		} else {
			omsAsnBillD = omsAsnBillDMapper.findById(dto.getRefBillLineId(), OmsAsnBillD.class);
		}
		if(omsAsnBillD!=null){
			dto.setItemCode(omsAsnBillD.getItemcode());
			//如果从页面上传入的效期不为空，则以页面传入的为准
			if(StringUtils.isNotBlank(dto.getBatchExpiredDate()) && StringUtils.isNotBlank(dto.getBatchProductionDate())){
				dto.setProductionDate(DateUtils.parse(dto.getBatchProductionDate()));
				dto.setExpiredDate(DateUtils.parse(dto.getBatchExpiredDate()));
			}else {
				if(StringUtils.isNotBlank(omsAsnBillD.getPdateFrom())){
					dto.setProductionDate(DateUtils.parse(omsAsnBillD.getPdateFrom()));
				}
				if(StringUtils.isNotBlank(omsAsnBillD.getValidUntil())){
					dto.setExpiredDate(DateUtils.parse(omsAsnBillD.getValidUntil()));
				}
			}


			OmsAsnBillH OmsAsnBillH = null;
			if(StringUtil.isEmpty(dto.getSupplierCode())){
				OmsAsnBillH=OmsAsnBillHMapper.findById(dto.getRefBillId(), OmsAsnBillH.class);
				if(!"2".equals(OmsAsnBillH.getRefBilltype())){
					BaseSupplierMst supplier = getSupplierById(OmsAsnBillH.getShipperid());
					if(supplier!=null){
						dto.setCargoOwnerId(OmsAsnBillH.getConsignorid());
						dto.setCargoOwnerCode(OmsAsnBillH.getConsignorcode());
						dto.setSupplierCode(supplier.getSupplierCode());
						dto.setCompanyCode(supplier.getSupplierCode());
						dto.setSupplierId(supplier.getSupplierId());
					}
					dto.setSupervisionType(0);
				}else{
					BaseCustomerMst shipper = getShipper(OmsAsnBillH.getShipperid());
					if(shipper!=null){
						dto.setCargoOwnerId(OmsAsnBillH.getConsignorid());
						dto.setCargoOwnerCode(OmsAsnBillH.getConsignorcode());
						dto.setShipperCode(shipper.getCustomerCode());
						dto.setCompanyCode(shipper.getCustomerCode());
						dto.setShipperId(shipper.getCustomerId());
					}
					dto.setSupervisionType(1);
				}
			}
			if(StringUtil.isEmpty(dto.getCargoOwnerCode()) && ToolKits.isNotEmpty(OmsAsnBillH)){//货主必填，to do
				BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(OmsAsnBillH.getConsignorid());
				if(baseCargoOwnerMst != null) {
					dto.setCargoOwnerId(baseCargoOwnerMst.getCargoOwnerId());
					dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
				}
			}
		}
	}

	@Override
	public void addSupervisionCodeAppendList(List<SupervisionCode> dtoList){
		for (int i = 0; i < dtoList.size(); i++) {
			SupervisionCode dto = dtoList.get(i);
			dto.setStage(4);
			spellCommonSupervisionCode(dto);
			addSupervisionCodeCoreAppend(dto);
		}
	}

	public void addSupervisionCodeCoreAppend(SupervisionCode dto) {
		String supervisionCode = dto.getSupervisionCode();
		if(StringUtils.isEmpty(supervisionCode) || !Pattern.compile("^[0-9]{20}$").matcher(supervisionCode).matches()){
			throw new BizException("监管码必须是20位数字");
		}
		String consignorId =StringUtils.isBlank(dto.getCargoOwnerId())? dto.getConsignorId():dto.getCargoOwnerId();
		BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(consignorId);
		if(baseCargoOwnerMst==null){
			throw new BizException("货主不能为空");
		}
		String refBillId = dto.getRefBillId();
		String refBillLineId = dto.getRefBillLineId();
		RcvHDTO rcvDTO=rcvHeadersMapper.findByPkId(refBillId);
		if (null!=rcvDTO && null!=rcvDTO.getAsnBillNum()) {
			dto.setSrcCode(rcvDTO.getAsnBillNum());
		}
		dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = Restrictions.eq("refBillLineId", refBillLineId);
		Restriction r4 = Restrictions.eq("supervisionCode", supervisionCode);
		Restriction r5 = Restrictions.and(r1,r2,r4);
		Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
		criteria11.setRestriction(r5);
		if(mapper.findCountByCriteria(criteria11) > 0L){
			throw new BizException("补录的监管码重复");
		}
		log.info("补录的监管码为：{}", supervisionCode);
		mapper.save(dto);
		String checkOnlyOne=dto.getWarehouseId()+"_"+dto.getSrcCode()+"_"+supervisionCode;
		redisTemplate.opsForValue().set("wms:scanCode:"+checkOnlyOne,1,1, TimeUnit.MINUTES);
		EtlMessage em = new EtlMessage();
		em.setId(dto.getId());
		em.setEtlType(EtlTypeConstants.bases_supervision_code);
		try {
			exchangeSender.send(em);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BizException("服务异常，请联系管理员");
		}
	}

	@Override
	public void addSupervisionCodeCore(SupervisionCode dto) {
		String supervisionCode = dto.getSupervisionCode();
		if(dto.getCodeType().equals("1")){
			if(StringUtils.isEmpty(supervisionCode) || !Pattern.compile("^[0-9]{20}$").matcher(supervisionCode).matches()){
				throw new BizException("监管码必须是20位数字");
			}
		}
		String srcCode = dto.getSrcCode();
		if(StringUtils.isEmpty(srcCode)){
			throw new BizException("订单不能为空");
		}
		String consignorId =StringUtils.isBlank(dto.getCargoOwnerId())? dto.getConsignorId():dto.getCargoOwnerId();
		BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(consignorId);
		if(baseCargoOwnerMst==null){
			throw new BizException("货主不能为空");
		}
		String warehouseId = dto.getWarehouseId();
		Restriction r1 = Restrictions.eq("warehouseId", warehouseId);
		Restriction r2 = Restrictions.eq("srcCode", srcCode);
		Restriction r3 = Restrictions.eq("supervisionCode", dto.getSupervisionCode());
		Restriction r4 = Restrictions.and(r1,r2,r3);
		Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
		criteria11.setRestriction(r4);
		if(mapper.findCountByCriteria(criteria11) > 0L){
//			if(StringUtils.isEmpty(dto.getCodeType())){
//				throw new BizException("扫描的监管码重复");
//			}else{
//				if(dto.getCodeType().equals("3")){
//					throw new BizException("扫描的序列号重复");
//				}
//			}
			if(StringUtils.isNotEmpty(dto.getCodeType())&&dto.getCodeType().equals("1")){
				throw new BizException("扫描的监管码重复");
			}
		}
		if(StringUtils.isBlank(dto.getItemCode())){
			String[] itemIds = {dto.getItemId()};
			RestMessage<List<BaseMtlItemMst>> itemResult = baseItemRemoteCaller.getListByIds(new HashSet<>(Arrays.asList(itemIds)));
			if (itemResult==null || !itemResult.isSuccess() || itemResult.getData() == null || itemResult.getData().size() == 0) {
				throw new BizException("商品不能为空");
			}
			List<BaseMtlItemMst> itemList=itemResult.getData();
			if(itemList.size()>0){
				dto.setItemCode(itemList.get(0).getItemCode());
			}
		}
		dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
//		AssertUtils.notNull(dto.getWarehouseCode(), "入参warehouseCode不能为空");
//		AssertUtils.notNull(dto.getCargoOwnerCode(), "入参cargoOwnerCode不能为空");
//		AssertUtils.notNull(dto.getCompanyCode(), "入参companyCode不能为空");
//		AssertUtils.notNull(dto.getItemCode(), "入参itemCode不能为空");
		//AssertUtils.notNull(dto.getManufacturerLotNum(), "入参manufacturerLotNum不能为空");
		if(baseCargoOwnerMst != null) {
			Integer isCodeSecurePlat = baseCargoOwnerMst.getIsCodeSecurePlat();
			String enterpriseId = baseCargoOwnerMst.getEnterpriseId();
			if(StringUtils.isEmpty(enterpriseId)){
				throw new RuntimeException("baseCargoOwnerMst配置的enterpriseId为空");
			}
			if (isCodeSecurePlat !=null && isCodeSecurePlat == 2) {
				//查询系统配置的参数
				RestMessage<SysRegistry> restMessage = commonCaller.getRegistryInfo("refEntId",enterpriseId);
				if (!restMessage.isSuccess()) {
					throw new RuntimeException("未查询到 refEntId 的系统配置参数:" + restMessage.getMessage());
				}
				SysRegistry data1 = restMessage.getData();
				String refEntId = data1.getRegValue();

				RestMessage<SysRegistry> restMessage3 = commonCaller.getRegistryInfo("serverUrl",enterpriseId);
				if (!restMessage3.isSuccess()) {
					throw new RuntimeException("未查询到 serverUrl 的系统配置参数:" + restMessage.getMessage());
				}
				SysRegistry data3 = restMessage3.getData();
				String serverUrl = data3.getRegValue();

				RestMessage<SysRegistry> restMessage4 = commonCaller.getRegistryInfo("appKey",enterpriseId);
				if (!restMessage4.isSuccess()) {
					throw new RuntimeException("未查询到 appKey 的系统配置参数:" + restMessage.getMessage());
				}
				SysRegistry data4 = restMessage4.getData();
				String appKey = data4.getRegValue();

				RestMessage<SysRegistry> restMessage5 = commonCaller.getRegistryInfo("appSecret",enterpriseId);
				if (!restMessage5.isSuccess()) {
					throw new RuntimeException("未查询到 appSecret 的系统配置参数:" + restMessage.getMessage());
				}
				SysRegistry data5 = restMessage5.getData();
				String appSecret = data5.getRegValue();


//				TaobaoClient client = new DefaultTaobaoClient(serverUrl, appKey, appSecret);
//				AlibabaAlihealthDrugCodeKytQuerycodeRequest req = new AlibabaAlihealthDrugCodeKytQuerycodeRequest();
//				req.setCodes(dto.getSupervisionCode());//999枇杷膏
//				req.setRefEntId(refEntId);//企业唯一标识
//				try {
//					TaobaoResponse rsp = client.execute(req);
//					ObjectMapper mapper = new ObjectMapper();
//					JsonNode node = mapper.readTree(rsp.getBody());
//					String code_status = node.get("alibaba_alihealth_drug_code_kyt_querycode_response").get("result")
//							.get("models").get("code_full_info_dto").get(0).get("code_status_type_d_t_o").get("code_status").asText();
//					if ("E".equals(code_status)) {//code_status I核注O核销A激活C注销E错误码
//						throw new BizException("码上放心平台返回结果：错误码");
//					}
//					JsonNode produce_info_dto = node.get("alibaba_alihealth_drug_code_kyt_querycode_response").get("result")
//							.get("models").get("code_full_info_dto").get(0).get("code_produce_info_d_t_o").get("produce_info_list")
//							.get("produce_info_dto").get(0);
//					String batch_no = produce_info_dto.get("batch_no").asText();
//					String expire_date = produce_info_dto.get("expire_date").asText();
//					String produce_date_str = produce_info_dto.get("produce_date_str").asText();
//					if (!batch_no.equals(dto.getManufacturerLotNum())) {
//						throw new BizException("收货批号【" + dto.getManufacturerLotNum() + "】跟码上放心平台批号【" + batch_no + "】不一致");
//					}
////					Date dtoProductionDate = dto.getProductionDate();
////					if (dtoProductionDate == null) {
////						throw new BizException("生产日期为空");
////					}
////					String productionDate = DateUtils.format(dtoProductionDate, "yyyy-MM-dd");
////					if (StringUtils.isNotBlank(productionDate) && !productionDate.equals(produce_date_str)) {
////						throw new BizException("生产日期【" + productionDate + "】跟码上放心平台生产日期【" + produce_date_str + "】不一致");
////					}
////					Date dtoExpiredDate = dto.getExpiredDate();
////					if (dtoExpiredDate == null) {
////						throw new BizException("收货有效期至为空");
////					}
////					String expiredDate = DateUtils.format(dtoExpiredDate, "yyyy-MM-dd");
////					if (StringUtils.isNotBlank(expiredDate) && !expiredDate.equals(expire_date)) {
////						throw new BizException("收货有效期至为空").putParam("code", "703");
////						//return RestMessage.newInstance(true,"703", "success","有效期至【"+expiredDate+"】跟码上放心平台【"+expire_date+"】不一致");
////					}
//				} catch (ApiException e) {
//					log.error("调用码上放心平台异常", e);
//					//throw new BizException("调用码上放心平台异常，请联系管理员");
//				} catch (BizException e) {
//					log.error("调用码上放心平台异常", e);
//					//throw new BizException(e.getMessage());
//				} catch (Exception e) {
//					log.error("调用码上放心平台异常", e);
//					//throw new BizException("系统异常");
//				}
			}
		}
		log.info("保存的监管码为：{}", dto.getSupervisionCode());
		mapper.save(dto);
		String checkOnlyOne=warehouseId+"_"+srcCode+"_"+supervisionCode;
		redisTemplate.opsForValue().set("wms:scanCode:"+checkOnlyOne,1,1, TimeUnit.MINUTES);
//        EtlMessage em = new EtlMessage();
//        em.setId(dto.getId());
//        em.setEtlType(EtlTypeConstants.bases_supervision_code);
//        try {
//            exchangeSender.send(em);
//        } catch (Exception e) {
//            e.printStackTrace();
//            throw new BizException("服务异常，请联系管理员");
//        }
	}

	@Override
	public SuperviseResultDTO itemsByBill(String refBillId,String refBillLineId) {
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = Restrictions.eq("unlock", 1);
		Restriction r3 = Restrictions.and(r1,r2);
		criteria1.setRestriction(r3);
//		if(mapper.findCountByCriteria(criteria1)!=0L){
//			throw new BizException("该单据已解锁");
//		}
		Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
		Restriction r11 = Restrictions.eq("refBillId", refBillId);
		Restriction r22 = Restrictions.eq("refBillLineId", refBillLineId);
		Restriction r33 = Restrictions.and(r11,r22);
		criteria11.setRestriction(r33);
		criteria11.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> list = mapper.findByCriteria(criteria11);
		if(list==null || list.size()==0){
			return null;
		}
		List<SupervisionCode> superviseCodesModal = new ArrayList<>();
		List supervisionCodesStrList=new ArrayList();
		for (int i = 0; i < list.size(); i++) {
			String supervisionCode = list.get(i).getSupervisionCode();
			if(!supervisionCodesStrList.contains(supervisionCode)){
				supervisionCodesStrList.add(supervisionCode);
				superviseCodesModal.add(list.get(i));
			}
		}
		return SuperviseResultDTO.newInstance(isSupervised(list.get(0),list.size()),false,list.get(0).getPackLevel(),supervisionCodesStrList,superviseCodesModal);
	}

	@Override
	public void checkSupervisionCode(SupervisionCode dto) {
		long count = mapper.findCountByMap(MapUtils.put("itemId", dto.getItemId()).put("manufacturerLotNum", dto.getManufacturerLotNum()).put("supervisionCode", dto.getSupervisionCode()).getMap(), SupervisionCode.class);
		if(count <= 0){
			throw new BizException("监管码不存在或监管码商品批号不匹配!");
		}
	}

	@Override
	public SuperviseResultDTO itemsByBill1(String refBillId,String refBillLineId) {
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = Restrictions.eq("unlock", 1);
		Restriction r3 = Restrictions.and(r1,r2);
		criteria1.setRestriction(r3);
		Boolean isUnLock = false;
		if(mapper.findCountByCriteria(criteria1)!=0L){
			isUnLock = true;
			return SuperviseResultDTO.newInstance(true,isUnLock,null,null,null);
		}
		Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
		Restriction r11 = Restrictions.eq("refBillId", refBillId);
		Restriction r22 = Restrictions.eq("refBillLineId", refBillLineId);
		Restriction r33 = Restrictions.and(r11,r22);
		criteria11.setRestriction(r33);
		criteria11.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> list = mapper.findByCriteria(criteria11);
		Boolean isCompleted = false;
		if(list==null || list.size()==0){
			return SuperviseResultDTO.newInstance(isCompleted,isUnLock,null,null,null);
		}
		List<SupervisionCode> superviseCodesModal = new ArrayList<>();
		List supervisionCodesStrList=new ArrayList();
		BigDecimal pieceQty = new BigDecimal(list.get(0).getPieceQty());
		BigDecimal packSize = new BigDecimal(0);
		for (int i = 0; i < list.size(); i++) {
			String supervisionCode = list.get(i).getSupervisionCode();
			packSize = packSize.add(new BigDecimal(list.get(i).getPackSize()));
			if(!supervisionCodesStrList.contains(supervisionCode)){
				supervisionCodesStrList.add(supervisionCode);
				superviseCodesModal.add(list.get(i));
			}
		}
		if(pieceQty.compareTo(packSize)==0){
			isCompleted = true;
		}
		return SuperviseResultDTO.newInstance(isCompleted,isUnLock,list.get(0).getPackLevel(),supervisionCodesStrList,superviseCodesModal);
	}

	@Override
	public SuperviseResultDTO itemsByBillYj(String refBillId,String refBillLineId) {
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = Restrictions.eq("unlock", 1);
		Restriction r3 = Restrictions.and(r1,r2);
		criteria1.setRestriction(r3);
		Boolean isUnLock = false;
		if(mapper.findCountByCriteria(criteria1)!=0L){
			isUnLock = true;
			return SuperviseResultDTO.newInstance(true,isUnLock,null,null,null);
		}
		Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
		Restriction r11 = Restrictions.eq("refBillId", refBillId);
		Restriction r22 = Restrictions.eq("refBillLineId", refBillLineId);
		Restriction r33 = Restrictions.and(r11,r22);
		criteria11.setRestriction(r33);
		criteria11.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> list = mapper.findByCriteria(criteria11);
		Boolean isCompleted = false;
		if(list==null || list.size()==0){
			return SuperviseResultDTO.newInstance(isCompleted,isUnLock,null,null,null);
		}
		List<SupervisionCode> superviseCodesModal = new ArrayList<>();
		List supervisionCodesStrList=new ArrayList();
		BigDecimal pieceQty = new BigDecimal(list.get(0).getPieceQty());
		BigDecimal packSize = new BigDecimal(0);
		for (int i = 0; i < list.size(); i++) {
			String supervisionCode = list.get(i).getSupervisionCode();
			packSize = packSize.add(new BigDecimal(list.get(i).getPackSize()));
			if(!supervisionCodesStrList.contains(supervisionCode)){
				supervisionCodesStrList.add(supervisionCode);
				superviseCodesModal.add(list.get(i));
			}
		}
		if(pieceQty.compareTo(packSize)==0){
			isCompleted = true;
		}
		return SuperviseResultDTO.newInstance(isCompleted,isUnLock,list.get(0).getPackLevel(),supervisionCodesStrList,superviseCodesModal);
	}

	@Override
	public SuperviseResultDTO findCodesByAllRefBillLineId(SupervisionCodeVO codeVO) {
		if(ObjectUtil.isEmpty(codeVO)) {
			throw new NullParameterException("查询参数不能为空");
		}
		String refBillId = codeVO.getRefBillId();
		String refBillLineId = codeVO.getRefBillLineId();
		String creator = codeVO.getUserId();
		String userId = codeVO.getUserId();
		Integer pageNum = codeVO.getPageNum();
		Integer pageSize = codeVO.getPageSize();
		if(queryIsUnlock(refBillId)) {
			return SuperviseResultDTO.newInstance(false,true,null,null,null);
		}

		// 根据上级单据ID查询扫描的监管码记录
		List<SupervisionCode> refBillIdCodeList = getSupervisionCodeListByRefBillId(refBillId,userId);
		if(ObjectUtil.isEmpty(refBillIdCodeList)) {
			return SuperviseResultDTO.newInstance(false,null,"0",new ArrayList<String>(),null);
		}

		// 判断单据是否解锁
//		long unLockCount = refBillIdCodeList.stream().filter(o -> Integer.valueOf(1).equals(o.getUnlock())).count();
//		if(unLockCount > 0) {
//			return SuperviseResultDTO.newInstance(false,true,null,null,null);
//		}

		// 查询监管码分页记录
		SuperviseResultDTO superviseResultDTO = getSuperviseResultDTO(refBillId, refBillLineId, creator,refBillIdCodeList, pageNum, pageSize);

		// 判断传入订单行是否都扫描完成
		Boolean isBillCompleted = superviseResultDTO.getComplete();
		if(ObjectUtil.isNotEmpty(codeVO.getOtherSelectBillList())) {
			isBillCompleted = getBillCompleted(refBillIdCodeList, codeVO.getOtherSelectBillList());
		}
		superviseResultDTO.setBillComplete(isBillCompleted);

		return superviseResultDTO;
	}

	@Override
	public void deleteCodesByBill(List<String> refBillLineIds) {
		if(CollectionUtil.isEmpty(refBillLineIds)){
			throw new BizException("关联行ID不能为空");
		}
		Criteria crt = Criteria.forClass(SupervisionCode.class);
		crt.restrictionBuilder().in("refBillLineId",refBillLineIds.toArray());
		crt.buildRestriction();
		mapper.deleteByCriteria(crt);
	}

	/**
	 * 判断传入订单行是否扫描完成
	 **/
	public Boolean getBillCompleted(List<SupervisionCode> refBillIdCodeList, List<SupervisionCodeVO> otherSelectBillList) {
		if(ObjectUtil.isEmpty(otherSelectBillList)) {
			return false;
		}

		// 扫码记录的上级订单id
		String refBillId = refBillIdCodeList.get(0).getRefBillId();

		// 选中的其它上级订单id
		List<String> otherRefBillIdList = otherSelectBillList.stream().filter(o -> ObjectUtil.notEqual(refBillId, o.getRefBillId()))
				.map(o -> o.getRefBillId()).distinct().collect(Collectors.toList());
		// 如果存在其他上级订单id，则查询扫码记录
		List<SupervisionCode> otherRefBillIdCodeList = new ArrayList<>();
		if(otherRefBillIdList.size() > 0) {
			otherRefBillIdCodeList = getSupervisionCodeListByRefBillIdList(otherRefBillIdList);
		}
		otherRefBillIdCodeList.addAll(refBillIdCodeList);

		for(SupervisionCodeVO codeVO : otherSelectBillList) {
			// 获取当前行的扫码记录
			List<SupervisionCode> codeList = otherRefBillIdCodeList.stream().filter(o -> ObjectUtil.equal(codeVO.getRefBillId(), o.getRefBillId())
					&& ObjectUtil.equal(codeVO.getRefBillLineId(), o.getRefBillLineId())).collect(Collectors.toList());
			if(ObjectUtil.isEmpty(codeList)) {
				return false;
			}

			// 订单行数量
			BigDecimal sumPieceQty = BigDecimal.ZERO;
			String pieceQtyStr = codeList.get(0).getPieceQty();
			if(ObjectUtil.isNotEmpty(pieceQtyStr)) {
				sumPieceQty = new BigDecimal(pieceQtyStr);
			}
			// 已扫包装数量
			BigDecimal sumPackSize = BigDecimal.ZERO;
			for(SupervisionCode supervisionCode : codeList) {
				// 累加包装数量
				String packSizeStr = supervisionCode.getPackSize();
				if(ObjectUtil.isNotEmpty(packSizeStr)) {
					sumPackSize = sumPackSize.add(new BigDecimal(packSizeStr));
				}
			}
			// 订单行未扫码完成
			if(sumPieceQty.compareTo(sumPackSize) > 0){
				return false;
			}
		}
		return true;
	}

	public List<SupervisionCode> getSupervisionCodeListByRefBillIdList(List<String> refBillIdList) {
		// 根据上级单据ID查询扫描的监管码记录
		FieldSelector codeField = FieldSelector.newInstance().include(new String[]{"id", "refBillId", "refBillLineId",
				"supervisionCode", "packLevel", "stage", "packSize", "pieceQty", "unlock", "itemName"});
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		criteria1.setRestriction(Restrictions.in("refBillId", refBillIdList.toArray()));
		criteria1.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> refBillIdCodeList = mapper.findFieldsByCriteria(codeField, criteria1);
		return refBillIdCodeList;
	}

	public List<SupervisionCode> getSupervisionCodeListByRefBillId(String refBillId,String userId) {
		// 根据上级单据ID查询扫描的监管码记录
		FieldSelector codeField = FieldSelector.newInstance().include(new String[]{"id", "refBillId", "refBillLineId",
				"supervisionCode", "packLevel", "stage", "packSize", "pieceQty", "unlock", "itemName"});
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = StringUtils.isNotEmpty(userId)?Restrictions.eq("creator", userId):null;
		criteria1.setRestriction(Restrictions.and(r1,r2));
		criteria1.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> refBillIdCodeList = mapper.findFieldsByCriteria(codeField, criteria1);
		return refBillIdCodeList;
	}

	public SuperviseResultDTO getSuperviseResultDTO(String refBillId, String refBillLineId,String creator,
													List<SupervisionCode> refBillIdCodeList,
													Integer pageNum, Integer pageSize) {
		// 上级单据行ID对应的监管码记录
		List<SupervisionCode> list = refBillIdCodeList.stream().filter(o -> ObjectUtil.isNotEmpty(refBillLineId)
				&& refBillLineId.equals(o.getRefBillLineId())).collect(Collectors.toList());
		if(ObjectUtil.isEmpty(list)) {
			return SuperviseResultDTO.newInstance(false,null,"0",new ArrayList<String>(),null);
		}
		List<SupervisionCode> superviseCodesModal = new ArrayList<>();
		List supervisionCodesStrList=new ArrayList();
		BigDecimal pieceQty = new BigDecimal(list.get(0).getPieceQty());
		BigDecimal packSize = new BigDecimal(0);
		for (int i = 0; i < list.size(); i++) {
			String supervisionCode = list.get(i).getSupervisionCode();
			if(!supervisionCodesStrList.contains(supervisionCode)){
				supervisionCodesStrList.add(supervisionCode);
				superviseCodesModal.add(list.get(i));
				// 累加包装数量
				String codePackSize = list.get(i).getPackSize();
				if(ObjectUtil.isNotEmpty(codePackSize)) {
					packSize = packSize.add(new BigDecimal(codePackSize));
				}
			}
		}

		// 是否扫码完成
		Boolean isCompleted = false;
		if(pieceQty.compareTo(packSize) <= 0){
			isCompleted = true;
		}

		// 分页查询
		Page<SupervisionCode> supervisionCodePage = getSupervisionCodePage(refBillId, refBillLineId, creator, pageNum, pageSize);

		SuperviseResultDTO superviseResultDTO = new SuperviseResultDTO();
		superviseResultDTO.setComplete(isCompleted);
		superviseResultDTO.setIsUnLock(false);
		superviseResultDTO.setPackLevel(list.get(0).getPackLevel());
		// 分页数据
		superviseResultDTO.setSuperviseCodes(supervisionCodesStrList);
		superviseResultDTO.setSuperviseCodesModal(supervisionCodePage.getList());
		superviseResultDTO.setTotalCount(supervisionCodePage.getTotalCount());
		superviseResultDTO.setPageCount(supervisionCodePage.getPageCount());
		superviseResultDTO.setPageNum(supervisionCodePage.getPageNum());
		superviseResultDTO.setPageSize(supervisionCodePage.getPageSize());
		superviseResultDTO.setStartRow(supervisionCodePage.getStartRow());
		superviseResultDTO.setEndRow(supervisionCodePage.getEndRow());
		// 计算实扫数
		SupervisionCode supervisionCode = new SupervisionCode();
		setScanedSupervisionCodeQty(supervisionCode, superviseCodesModal);
		superviseResultDTO.setMaxScanedQty(supervisionCode.getMaxScanedQty());
		superviseResultDTO.setMiddleScanedQty(supervisionCode.getMiddleScanedQty());
		superviseResultDTO.setMinScanedQty(supervisionCode.getMinScanedQty());

		return superviseResultDTO;
	}

	/**
	 * 计算监管码实扫数
	 **/
	public void setScanedSupervisionCodeQty(SupervisionCode supervisionCode, List<SupervisionCode> superviseCodesModalList) {
		// 实扫大包装数
		int maxScanedQty = 0;
		// 实扫中包装数
		int middleScanedQty = 0;
		// 实扫小包装数
		int minScanedQty = 0;
		// 监管码扫描记录
		if(superviseCodesModalList!=null){
			for(SupervisionCode supervisionCodeModal : superviseCodesModalList) {
				if(StringUtils.isBlank(supervisionCodeModal.getPackLevel())){
					continue;
				}
				switch (supervisionCodeModal.getPackLevel()) {
					case "0":
						// 大包装
						maxScanedQty++;
						break;
					case "1":
						// 中包装
						middleScanedQty++;
						break;
					case "2":
						// 小包装
						minScanedQty++;
						break;
					default:
						break;
				}
			}
		}
		supervisionCode.setMaxScanedQty(StrUtil.toString(maxScanedQty));
		supervisionCode.setMiddleScanedQty(StrUtil.toString(middleScanedQty));
		supervisionCode.setMinScanedQty(StrUtil.toString(minScanedQty));
	}


	public Page<SupervisionCode> getSupervisionCodePage(String refBillId, String refBillLineId, String creator,
														Integer pageNum, Integer pageSize) {
		// 分页查询扫描的监管码记录
		pageNum = ObjectUtil.defaultIfNull(pageNum ,1);
		pageSize = ObjectUtil.defaultIfNull(pageSize ,9999);
		PageUtils.startPage(pageNum, pageSize);
		FieldSelector codeField = FieldSelector.newInstance().include(new String[]{"id", "refBillId", "refBillLineId",
				"supervisionCode", "packLevel", "stage", "packSize", "pieceQty", "unlock", "itemName"});
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		criteria1.setRestriction(Restrictions.and(Restrictions.eq("refBillId", refBillId),
				Restrictions.eq("refBillLineId", refBillLineId),Restrictions.eq("creator", creator)));
		criteria1.setOrder(Order.newInstance().desc("gmtModified"));
		List<SupervisionCode> refBillIdCodeList = mapper.findFieldsByCriteria(codeField, criteria1);

		return PageUtils.getPage(refBillIdCodeList);
	}



	@Override
	public Boolean isSupervised(List<SupervisionCode> list) {
		try {
				if(queryIsUnlock(list.get(0).getRefBillId())){
					return true;
				}
			for (int i = 0; i < list.size(); i++) {
				SupervisionCode supervisionCode=list.get(i);
				Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
				Restriction r11 = Restrictions.eq("refBillId", supervisionCode.getRefBillId());
				Restriction r22 = Restrictions.eq("refBillLineId", supervisionCode.getRefBillLineId());
				Restriction r33 = Restrictions.and(r11,r22);
				criteria11.setRestriction(r33);
				List<SupervisionCode> dbList = mapper.findByCriteria(criteria11);
				if(dbList==null || dbList.size()==0){
					return false;
				}
				if(!isSupervised1(dbList,dbList.get(0).getPieceQty())){
					return false;
				}
			}
		} catch (Exception e) {
			log.error("isSupervised",e);
			throw new BizException("数据异常，请联系管理员");
		}
		return true;
	}

	@Override
	public Boolean isSupervisedReject(List<SupervisionCode> list) {
		Boolean finish = false;
		if(CollectionUtil.isNotEmpty(list)){
			Map<String, List<SupervisionCode>> collect = list.stream().filter(x -> StringUtils.isNotEmpty(x.getRefBillId()) && StringUtils.isNotEmpty(x.getRefBillLineId())).collect(Collectors.groupingBy(x -> x.getRefBillId() + x.getRefBillLineId()));
			for (List<SupervisionCode> value : collect.values()) {
				BigDecimal reduce = value.stream().map(x -> x.getRejectQty()==null?BigDecimal.ZERO:x.getRejectQty()).reduce(BigDecimal.ZERO, BigDecimal::add);
				String refBillId = value.get(0).getRefBillId();
				String refBillLineId = value.get(0).getRefBillLineId();
				BigDecimal receiveQty = value.get(0).getReceiveQty();
				BigDecimal scanQty = receiveQty.subtract(reduce);
				Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
				Restriction r11 = Restrictions.eq("refBillId", refBillId);
				Restriction r22 = Restrictions.eq("refBillLineId", refBillLineId);
				Restriction r33 = Restrictions.and(r11,r22);
				criteria11.setRestriction(r33);
				List<SupervisionCode> dbList = mapper.findByCriteria(criteria11);
				BigDecimal codeQty = dbList.stream().map(x -> new BigDecimal(x.getPackSize())).reduce(BigDecimal.ZERO, BigDecimal::add);
				if(scanQty.compareTo(codeQty)==0){
					finish = true;
				}else{
					finish = false;
					break;
				}
			}
		}
		return finish;
	}

	//计算扫码次数
	private boolean isSupervised(SupervisionCode dbSupervisionCode, Integer size) {
		if(dbSupervisionCode.getPieceQty()==null || dbSupervisionCode.getPackSize()==null){//无法计算应扫描数
			return false;
		}
		Integer pieceQty = new BigDecimal(dbSupervisionCode.getPieceQty()).intValue();
		Integer packSize = new BigDecimal(dbSupervisionCode.getPackSize()).intValue();
		return (pieceQty/packSize+pieceQty%packSize)==size;
	}

	private boolean isSupervised1(List<SupervisionCode> dbSupervisionCode, String pieceQty) {
		if(pieceQty==null||(dbSupervisionCode==null || dbSupervisionCode.size()==0)){//无法计算应扫描数
			return false;
		}
		BigDecimal reduce = dbSupervisionCode.stream().map(x -> new BigDecimal(x.getPackSize())).reduce(BigDecimal.ZERO, BigDecimal::add);
		return new BigDecimal(pieceQty).compareTo(reduce)==0;
	}

	private boolean queryIsUnlock(String refBillId) {
		Criteria criteria1 = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("refBillId", refBillId);
		Restriction r2 = Restrictions.eq("unlock", 1);
		Restriction r3 = Restrictions.and(r1,r2);
		criteria1.setRestriction(r3);
		return mapper.findCountByCriteria(criteria1)!=0L;
	}

	@Override
	public List<? extends IsSuperviseDTO> isSupervise(List<? extends IsSuperviseDTO> list,Integer stage) {
		//请求商品信息
		List<BaseMtlItemMst> itemList =null;
		Set itemSet = list.stream().filter(p -> !StringUtils.isBlank(p.getItemId())).map(IsSuperviseDTO::getItemId).collect(Collectors.toSet());
		if(itemSet!=null && itemSet.size()>0){
			RestMessage<List<BaseMtlItemMst>> itemResult=baseItemRemoteCaller.getListByIds(itemSet);
			itemList=itemResult.getData();
		}
		//请求货主信息
		Map<String,BaseCargoOwnerMst> ownerMap=null;
		Set ownerSet = list.stream().filter(p -> !StringUtils.isBlank(p.getConsignorId())).map(IsSuperviseDTO::getConsignorId).collect(Collectors.toSet());
		if(ownerSet!=null && ownerSet.size()>0) {
			RestMessage<Map<String, BaseCargoOwnerMst>> ownerResult = chainRemoteCaller.getByIds(ownerSet);
			ownerMap=ownerResult.getData();
		}
		//请求客户信息
		List<BaseCustomerMst> customerList=null;
		if(stage>0){
			Set customerSet = list.stream().filter(t -> !StringUtils.isBlank(t.getShipperId())).map(IsSuperviseDTO::getShipperId).collect(Collectors.toSet());;
			if(customerSet!=null && customerSet.size()!=0){
				BaseCustomerMstRequestVO baseCustomerMstRequestVO=new BaseCustomerMstRequestVO();
				baseCustomerMstRequestVO.setIncludeSearchIds(customerSet);
				RestMessage<List<BaseCustomerMst>> customerResult = chainRemoteCaller.findAll(baseCustomerMstRequestVO);
				if (customerResult!=null && customerResult.isSuccess() && customerResult.getData() != null && customerResult.getData().size() > 0) {
					customerList=customerResult.getData();
				}
			}
		}
		BaseWmsWarehouseMst wmsWarehouseMst=null;//请求仓库信息
		for (int i = 0; i < list.size(); i++) {
			IsSuperviseDTO dto=list.get(i);
			String itemId=dto.getItemId();
			BaseMtlItemMst baseMtlItemMst = itemList.stream().filter(model -> model!=null && itemId.equals(model.getItemId())).
					findFirst().orElse(null);
            Integer itemIsSeque = 0;
			if(baseMtlItemMst!=null && baseMtlItemMst.getBaseMtlItemWms()!=null&&baseMtlItemMst.getBaseMtlItemWms().getItemIsSeque()!=null&&baseMtlItemMst.getBaseMtlItemWms().getItemIsSeque()==1){
                itemIsSeque = 1;
            }
			if(dto.getIsSupervise()!=null&&dto.getIsSupervise()==0&&itemIsSeque==0){//设置不扫描监管码
				dto.setNoSuperviseReason("dto.getIsSupervise()!=null");
				continue;
			}
			dto.setIsSupervise(0);
			if(itemList==null || itemList.size()==0){
				dto.setNoSuperviseReason("itemList==null");
				continue;
			}
			if(ownerMap==null){
				dto.setNoSuperviseReason("ownerMap==null");
				continue;
			}
			Integer businessType=0;//业务类型：0=入库， 1=出库，2=库内
			//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
			if(StringUtils.isBlank(itemId)){
				dto.setNoSuperviseReason("StringUtils.isBlank(itemId)");
				continue;
			}
			if((baseMtlItemMst==null || baseMtlItemMst.getBaseMtlItemHealth()==null
					|| baseMtlItemMst.getBaseMtlItemHealth().getItemHealthSuperviseflag()==null
					|| baseMtlItemMst.getBaseMtlItemHealth().getItemHealthSuperviseflag()!=1)&&itemIsSeque==0){
				dto.setNoSuperviseReason("商品数据不存在或不扫码");
				continue;
			}
			if(stage > 0){
				businessType=1;
//				if(dto.getBillType()!=null && "8".equals(dto.getBillType())){//代管出库8不需要扫描监管码
//					dto.setNoSuperviseReason("代管出库不需要扫描监管码");
//					continue;
//				}

				String warehouseId = dto.getWarehouseId();
				if(!StringUtils.isBlank(warehouseId)){
					if(wmsWarehouseMst==null){
						RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = baseWmsWarehouseCaller.warehouse(warehouseId);
						if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
							wmsWarehouseMst=itemResultWarehouse.getData();
						}
					}
					if(wmsWarehouseMst!=null && wmsWarehouseMst.getScanSupervisionCodeStage()!=null){
						Integer scanSupervisionCodeStage = wmsWarehouseMst.getScanSupervisionCodeStage();
						//扫描监管码节点：0=整件拣货、零货拣货 1=整件外复核、零货拣货 2=整件拣货、零货内复核 3=整件外复核、零货内复核
						//扫码阶段：0=入库质检 10=PC整件拣货 11=PC零货拣货 12=PC功能库房拣货 2=PC内复核 3=PC外复核 4=补录
						// 50=PDA整件拣货 51=PDA零货拣货 52=PDA功能库房拣货 6=PDA内复核 7=PDA外复核
						if(scanSupervisionCodeStage==0){
							if(stage!=10 && stage!=11 && stage!=12 && stage!=50 && stage!=51 && stage!=52){
								dto.setNoSuperviseReason("scanSupervisionCodeStage==0 stage="+stage);
								continue;
							}
						}
						if(scanSupervisionCodeStage==1){

							if(stage!=11 && stage!=12 && stage!=51 && stage!=52 && stage!=3 && stage!=7){
								dto.setNoSuperviseReason("scanSupervisionCodeStage==1 stage="+stage);
								continue;
							}
						}
						if(scanSupervisionCodeStage==2){
							Integer isCaseOrPiece=null;
							if(baseMtlItemMst.getBaseMtlItemWms()!=null){
								isCaseOrPiece = baseMtlItemMst.getBaseMtlItemWms().getIsCaseOrPiece();
							}

							if("726788113300975616".equals(warehouseId) && stage==51 &&
									isCaseOrPiece!=null && isCaseOrPiece==0){//红河仓52=PDA功能库房拣货,扫码

							}else if("726788113300975616".equals(warehouseId) && stage==2 &&
									isCaseOrPiece!=null && isCaseOrPiece==0){//红河仓2=PC内复核,整删合一不扫码
								continue;
							}else if(stage!=10 && stage!=50 && stage!=2 && stage!=6){
								dto.setNoSuperviseReason("scanSupervisionCodeStage==2 stage="+stage);
								continue;
							}
						}
						if(scanSupervisionCodeStage==3){
							if(stage!=3 && stage!=7 && stage!=2 && stage!=6){
								dto.setNoSuperviseReason("scanSupervisionCodeStage==3 stage="+stage);
								continue;
							}
						}
					}
				}
			}
			String ownerId = dto.getConsignorId();
			BaseCargoOwnerMst ownerMst=ownerMap.get(ownerId);
			if(ownerMst==null){
				dto.setNoSuperviseReason("货主为空");
				continue;
			}
			if(businessType==0 && (ownerMst.getIsInstockScanCode()==null || ownerMst.getIsInstockScanCode()!=1)){
				dto.setNoSuperviseReason("货主入库不扫码");
				continue;
			}
			if(businessType==1 && (ownerMst.getIsOutstockScanCode()==null || ownerMst.getIsOutstockScanCode()!=1)){
				dto.setNoSuperviseReason("货主出库不扫码");
				continue;
			}
			if(itemIsSeque==1){
				dto.setIsSupervise(2);
				continue;
			}
			if(businessType==1 && !"2".equals(dto.getBillType())){
				String shipperId = dto.getShipperId();
				if(StringUtils.isBlank(shipperId)){
					dto.setNoSuperviseReason("StringUtils.isBlank(shipperId)");
					continue;
				}
				if(customerList!=null){
					BaseCustomerMst baseCustomerMst = customerList.stream().filter(model -> model!=null && shipperId.equals(model.getCustomerId())).
							findFirst().orElse(null);
					if(baseCustomerMst==null || baseCustomerMst.getIsQrCodeSupervise()==null || baseCustomerMst.getIsQrCodeSupervise()!=1){
						dto.setNoSuperviseReason("客户不存在或不扫码");
						continue;
					}
				}
			}
			spellIsSupervise(dto, baseMtlItemMst);
		}
		log.info("isSupervise,result,list：{},stage：{}", JSON.toJSONString(list),stage);
		return list;
	}

	private void spellIsSupervise(IsSuperviseDTO dto, BaseMtlItemMst baseMtlItemMst) {
		dto.setIsSupervise(1);
		RestMessage<Map<String, List<BaseMtlItemUomConversions>>> uomConversionsByItemIds = baseItemRemoteCaller.getUomConversionsByItemIds(baseMtlItemMst.getItemId());
		if(!uomConversionsByItemIds.isSuccess()&&uomConversionsByItemIds.getData()==null){
			dto.setIsSupervise(0);
			dto.setNoSuperviseReason("StringUtils.isBlank(uomConversions)");
			return;
		}
		List<BaseMtlItemUomConversions> uomList = uomConversionsByItemIds.getData().get(baseMtlItemMst.getItemId());
		if(uomList!=null){
			dto.setMiddleSu("1");
			dto.setMinSu("1");
			for(BaseMtlItemUomConversions uomConversions:uomList){
				if("Y".equals(uomConversions.getMaxSu())){
					dto.setMaxSu(uomConversions.getConversionRate().toString());
				}
				if(!"Y".equals(uomConversions.getMinSu()) && !"Y".equals(uomConversions.getMaxSu())){
					dto.setMiddleSu(uomConversions.getConversionRate().toString());
				}
				if("Y".equals(uomConversions.getMinSu()) && !"Y".equals(uomConversions.getMaxSu())){
					dto.setMinSu(uomConversions.getConversionRate().toString());
				}
			}
		}
	}

	@Override
	public Page<SupervisionCode> page(SupervisionCode queryVO, Integer pageSize, Integer pageNum) {
		PageUtils.startPage(pageNum, pageSize);
		Criteria crt = Criteria.forClass(SupervisionCode.class);
		Restriction r1 = Restrictions.eq("warehouseId",queryVO.getWarehouseId());
		String refBillId = queryVO.getRefBillId();
		Restriction r2 = StringUtils.isEmpty(refBillId)?null:Restrictions.eq("refBillId", refBillId);
		Restriction r3 = StringUtils.isEmpty(refBillId)?null:Restrictions.eq("refBillId", refBillId);
		Restriction r4 = StringUtils.isEmpty(refBillId)?null:Restrictions.eq("refBillId", refBillId);
		crt.setOrder(Order.newInstance().desc("gmtCreate"));
		crt.setRestriction(Restrictions.and(r1,r2,r3,r4));
		List<SupervisionCode> list = mapper.findByCriteria(crt);
		if(list==null || list.size()==0){
			return PageUtils.getPage(list);
		}
		return PageUtils.getPage(list);

	}

	@Override
	public List<Supervise4CargoChange> findCargoChangeList(String cargoChangeBillNo) throws Exception {
		Map map=new HashMap();
		map.put("refBillNo",cargoChangeBillNo);
		List<Map> list = searchApi.searchForMap("querySupervise4CargoChange",map);
		if (ObjectUtils.isEmpty(list))
			return null;
		List<Supervise4CargoChange> inList=new ArrayList<>();
		List<Supervise4CargoChange> outList=new ArrayList<>();
		for (int i = 0; i < list.size(); i++) {
			Supervise4CargoChange dto= JsonUtils.parseJsonString(JsonUtils.toString(list.get(i)),
					new TypeReference<Supervise4CargoChange>(){});

			dto.setConsignorId(dto.getDestCargoOwnerId());
			dto.setItemId(dto.getDestItemId());
			inList.add(dto);

			dto.setConsignorId(dto.getSrcCargoOwnerId());
			dto.setShipperId(dto.getDestCargoOwnerId());
			dto.setItemId(dto.getSrcItemId());
			outList.add(dto);
		}
		isSupervise(inList,0);
		isSupervise(outList,3);
		List<Supervise4CargoChange> retList=new ArrayList<>();
		for (int i = 0; i < inList.size(); i++) {
			Supervise4CargoChange supervise4CargoChange = inList.get(i);
			Integer inBoundIsSupervise = supervise4CargoChange.getIsSupervise();
			Integer outBoundIsSupervise = outList.get(i).getIsSupervise();
			if(inBoundIsSupervise !=0 || outBoundIsSupervise !=0){
				Restriction r1 = Restrictions.eq("refBillId", supervise4CargoChange.getPoBillId());
				Restriction r2 = Restrictions.eq("refBillId", supervise4CargoChange.getOrderBillId());
				Restriction r3 = Restrictions.eq("refBillLineId", supervise4CargoChange.getResultId());
				Restriction or1 = Restrictions.and(Restrictions.or(r1, r2), r3);
				Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
				criteria11.setRestriction(or1);
				Integer pieceQty = supervise4CargoChange.getQuantity().intValue();
				Integer packSize = new BigDecimal(supervise4CargoChange.getMaxSu()).intValue();
				int totalCount = pieceQty / packSize + pieceQty % packSize;
				int scanCount = Long.valueOf(mapper.findCountByCriteria(criteria11)).intValue();
				if((scanCount < totalCount) || (scanCount == totalCount && inBoundIsSupervise==1 && outBoundIsSupervise==1)){
					if(inBoundIsSupervise ==0){
						supervise4CargoChange.setPoBillId(null);
					}
					if(outBoundIsSupervise ==0){
						supervise4CargoChange.setOrderBillId(null);
					}
					supervise4CargoChange.setTotalCount(totalCount);
					supervise4CargoChange.setScanCount(scanCount);
					retList.add(supervise4CargoChange);
				}
			}
		}
		return retList;
	}

	@Override
	public Supervise4CargoChangeDetail findCargoChangeDetail(String resultId) throws Exception {
		Map map=new HashMap();
		map.put("resultId",resultId);
		List<Map> list = searchApi.searchForMap("querySupervise4CargoChange",map);
		if (ObjectUtils.isEmpty(list))
			return null;
		Supervise4CargoChangeDetail dto= JsonUtils.parseJsonString(JsonUtils.toString(list.get(0)),
				new TypeReference<Supervise4CargoChangeDetail>(){});
		if(!StringUtils.isBlank(dto.getDestItemId())){
			String[] itemIds = {dto.getDestItemId()};
			RestMessage<List<BaseMtlItemMst>> itemResult = baseItemRemoteCaller.getListByIds(new HashSet<>(Arrays.asList(itemIds)));
			if (itemResult!=null && itemResult.isSuccess() && itemResult.getData() != null && itemResult.getData().size() == 1) {
				BaseMtlItemMst itemBaseInfoVO =itemResult.getData().get(0);
				dto.setCountryOriginName(itemBaseInfoVO.getCountryOriginId());
				dto.setManufacturerName(itemBaseInfoVO.getManufacturerId());
				dto.setCaseConversionRate(itemBaseInfoVO.getCaseConversionRate());
				dto.setSpecification(itemBaseInfoVO.getSpecification());
				dto.setCaseUom(itemBaseInfoVO.getCaseUom());
			}
		}
		if(!StringUtils.isBlank(dto.getPoBillId()) || !StringUtils.isBlank(dto.getOrderBillId())){
			String refBillId=StringUtils.isBlank(dto.getPoBillId())?dto.getOrderBillId():dto.getPoBillId();
			Restriction r1 = Restrictions.eq("refBillId", refBillId);
			Restriction r2 = Restrictions.eq("refBillLineId", resultId);
			Restriction r3 = Restrictions.and(r1, r2);
			Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
			criteria11.setRestriction(r3);
			Integer pieceQty = dto.getQuantity().intValue();
			Integer packSize = dto.getCaseConversionRate().intValue();
			dto.setTotalCount(pieceQty / packSize + pieceQty % packSize);
			dto.setScanCount(Long.valueOf(mapper.findCountByCriteria(criteria11)).intValue());
		}
		return dto;
	}

	@Override
	@Transactional
	public void addSupervisionCodeCargoChange(Supervise4CargoChangeDetail dto){
		BaseCargoOwnerMst srcBaseCargoOwnerMst = getCargoOwner(dto.getSrcCargoOwnerId());
		if(srcBaseCargoOwnerMst==null){
			throw new BizException("源货主异常");
		}
		BaseCargoOwnerMst destBaseCargoOwnerMst = getCargoOwner(dto.getDestCargoOwnerId());
		if(destBaseCargoOwnerMst==null){
			throw new BizException("目标货主异常");
		}
		SupervisionCode supervisionCode=new SupervisionCode();
		BeanUtils.copyProperties(dto,supervisionCode);
		supervisionCode.setPackSize(dto.getCaseConversionRate().toString());
		supervisionCode.setPieceQty(dto.getQuantity().toString());
		supervisionCode.setPackLevel("0");
		if(!StringUtils.isBlank(dto.getPoBillId())){//入库
			supervisionCode.setRefBillId(dto.getPoBillId());
			supervisionCode.setRefBillLineId(dto.getResultId());
			supervisionCode.setConsignorId(dto.getDestCargoOwnerId());
			supervisionCode.setSupplierId(dto.getSrcCargoOwnerId());
			supervisionCode.setSupplierCode(srcBaseCargoOwnerMst.getCargoOwnerCode());
			supervisionCode.setCompanyCode(srcBaseCargoOwnerMst.getCargoOwnerCode());
			supervisionCode.setItemId(dto.getSrcItemId());
			supervisionCode.setStage(0);
			addSupervisionCode(supervisionCode);
		}
		if(!StringUtils.isBlank(dto.getOrderBillId())){//出库
			supervisionCode.setRefBillId(dto.getOrderBillId());
			supervisionCode.setRefBillLineId(dto.getResultId());
			supervisionCode.setItemId(dto.getDestItemId());
			supervisionCode.setConsignorId(dto.getSrcCargoOwnerId());
			supervisionCode.setSupplierId(null);
			supervisionCode.setSupplierCode(null);
			supervisionCode.setShipperId(dto.getDestCargoOwnerId());
			supervisionCode.setShipperCode(destBaseCargoOwnerMst.getCargoOwnerCode());
			supervisionCode.setStage(2);
			addSupervisionCode(supervisionCode);
		}
	}

	//请求仓库信息
	private BaseWmsWarehouseMst getWarehouse(String warehouseId){
		if(com.prolog.framework.utils.StringUtils.isBlank(warehouseId)){
			return null;
		}
		RestMessage<BaseWmsWarehouseMst> itemResultWarehouse = baseWmsWarehouseCaller.warehouse(warehouseId);
		if (itemResultWarehouse.isSuccess() && itemResultWarehouse.getData() != null) {
			return itemResultWarehouse.getData();
		}
		return null;
	}

	//请求货主信息
	private BaseCargoOwnerMst getCargoOwner(String cargoOwnerId){
		if(com.prolog.framework.utils.StringUtils.isBlank(cargoOwnerId)){
			return null;
		}

		RestMessage<Map<String, BaseCargoOwnerMst>> result = chainClient.getByIds(new HashSet<>(Arrays.asList(new String[]{cargoOwnerId})));
		if (result.isSuccess() && result.getData() != null) {
			return result.getData().get(cargoOwnerId);
		}
		return null;
	}

	//请求货主信息
	private BaseCustomerMst getShipper(String id){
		if(com.prolog.framework.utils.StringUtils.isBlank(id)){
			return null;
		}

		BaseCustomerMstRequestVO baseCustomerMstRequestVO=new BaseCustomerMstRequestVO();
		baseCustomerMstRequestVO.setIncludeSearchIds(new HashSet<>(Arrays.asList(new String[]{id})));
		RestMessage<List<BaseCustomerMst>> customerResult = chainRemoteCaller.findAll(baseCustomerMstRequestVO);
		if (customerResult.isSuccess() && customerResult.getData() != null && customerResult.getData().size()>0) {
			return customerResult.getData().get(0);
		}
		return null;
	}

	//请求货主信息
	private BaseSupplierMst getSupplierById(String id){
		if(com.prolog.framework.utils.StringUtils.isBlank(id)){
			return null;
		}
		RestMessage<BaseSupplierMst> customerResult = chainRemoteCaller.findOne(id);
		if (customerResult.isSuccess() && customerResult.getData() != null) {
			return customerResult.getData();
		}
		return null;
	}

	@Override
	public Page<SupervisionCode> querySupervisionCodedList(List<SupervisionCode> supervisionCodeList) {
		List<SupervisionCode> rsList = new ArrayList<>();
		SuperviseResultDTO superviseResultDTO = null;
		for (SupervisionCode supervisionCode:supervisionCodeList) {
			superviseResultDTO = itemsByBill1(supervisionCode.getRefBillId(),supervisionCode.getRefBillLineId());
			if (null != superviseResultDTO && !superviseResultDTO.isComplete()) {
				Integer actualNum = 0;
				if(superviseResultDTO.getSuperviseCodes()!=null){
					actualNum = superviseResultDTO.getSuperviseCodes().size();
				}
				supervisionCode.setActualQuantity(actualNum.toString());
				supervisionCode.setPackLevel(superviseResultDTO.getPackLevel());
				rsList.add(supervisionCode);
			} else if (null == superviseResultDTO) {
				supervisionCode.setActualQuantity("0");
				supervisionCode.setPackLevel(null);
				rsList.add(supervisionCode);
			}
		}
		return PageUtils.getPage(rsList);
	}

	@Override
	public void delIds(List<String> pkIdList) {
		List<SupervisionCode> list = this.mapper.findByIds(SupervisionCode.class, pkIdList.toArray(), null);
		if(pkIdList.size()!=list.size()){
			throw new BizException("删除监管码数据错误");
		}
		if(list.stream().filter(t->"20".equals(t.getStatus())).count()>0L){
			throw new BizException("已上传不能删除");
		}
		pkIdList.stream().forEach(p -> this.mapper.deleteById(p, SupervisionCode.class));
	}


	@Override
	public void addSupervisionCodeRqcRF(List<SupervisionCode> list){
		log.info("addSupervisionCode,dto="+JSON.toJSONString(list));
		AssertUtils.isNotTrue(list==null || list.size()==0, "入参不能为空");
        for(SupervisionCode dto :  list){
			String refBillId = dto.getRefBillId();
			AssertUtils.notNull(refBillId, "单据Id不能为空");
			Integer stage = dto.getStage();
			AssertUtils.notNull(stage, "入参stage不能为空");
			dto.setUnlock(0);
			String supervisionCode = dto.getSupervisionCode();
			AssertUtils.notNull(supervisionCode, "追溯码不能为空");
			String refBillLineId = dto.getRefBillLineId();
			AssertUtils.notNull(refBillLineId, "单据明细Id不能为空");
			String warehouseId = dto.getWarehouseId();
			if(StringUtil.isEmpty(dto.getWarehouseCode())){
				BaseWmsWarehouseMst baseWmsWarehouseMst = getWarehouse(warehouseId);
				if(baseWmsWarehouseMst!=null){
					dto.setWarehouseCode(baseWmsWarehouseMst.getWarehouseCode());
				}
			}
			spellCommonSupervisionCode(dto);
			buildSupervisionCodeInbound(dto);
			if(StringUtils.isEmpty(supervisionCode) || !Pattern.compile("^[0-9]{20}$").matcher(supervisionCode).matches()){
				throw new BizException("监管码必须是20位数字");
			}
			String srcCode = dto.getSrcCode();
			if(StringUtils.isEmpty(srcCode)){
				throw new BizException("订单不能为空");
			}
			String consignorId =StringUtils.isBlank(dto.getCargoOwnerId())? dto.getConsignorId():dto.getCargoOwnerId();
			BaseCargoOwnerMst baseCargoOwnerMst = getCargoOwner(consignorId);
			if(baseCargoOwnerMst==null){
				throw new BizException("货主不能为空");
			}
			Restriction r1 = Restrictions.eq("srcCode", srcCode);
			Restriction r2 = Restrictions.eq("warehouseId", warehouseId);
			Restriction r3 = Restrictions.eq("supervisionCode", dto.getSupervisionCode());
			Restriction r4 = Restrictions.and(r1,r2,r3);
			Criteria criteria11 = Criteria.forClass(SupervisionCode.class);
			criteria11.setRestriction(r4);
			if(mapper.findCountByCriteria(criteria11) > 0L){
				if(StringUtils.isEmpty(dto.getCodeType())){
					throw new BizException("扫描的监管码重复");
				}else{
					if(dto.getCodeType().equals("3")){
						throw new BizException("扫描的序列号重复");
					}
				}
			}
			if(StringUtils.isBlank(dto.getItemCode())){
				String[] itemIds = {dto.getItemId()};
				RestMessage<List<BaseMtlItemMst>> itemResult = baseItemRemoteCaller.getListByIds(new HashSet<>(Arrays.asList(itemIds)));
				if (itemResult==null || !itemResult.isSuccess() || itemResult.getData() == null || itemResult.getData().size() == 0) {
					throw new BizException("商品不能为空");
				}
				List<BaseMtlItemMst> itemList=itemResult.getData();
				if(itemList.size()>0){
					dto.setItemCode(itemList.get(0).getItemCode());
				}
			}
			dto.setCargoOwnerCode(baseCargoOwnerMst.getCargoOwnerCode());
		}
		mapper.saveBatch(list);
	}

	@Override
	public Object batchAdd(List<SupervisionCode> supervisionCodes) {
		return mapper.saveBatch(supervisionCodes);
	}

}
