package nccloud.pubimpl.ic.pub.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import nc.bs.framework.common.InvocationInfoProxy;
import nc.bs.framework.common.NCLocator;
import nc.bs.ic.pub.env.ICBSContext;
import nc.impl.pubapp.bd.material.assistant.MarAssistantCheckUtils;
import nc.impl.pubapp.pattern.database.DataAccessUtils;
import nc.itf.ic.onhand.OnhandResService;
import nc.itf.scmpub.reference.uap.bd.customer.CustomerPubService;
import nc.itf.scmpub.reference.uap.bd.supplier.SupplierPubService;
import nc.itf.scmpub.reference.uap.group.SysInitGroupQuery;
import nc.pubitf.ic.reserve.ReserveInOut;
import nc.pubitf.uapbd.IMaterialPubService_C;
import nc.pubitf.uapbd.assistant.IMarAssistantPubService;
import nc.vo.bd.material.MaterialVO;
import nc.vo.bd.userdefrule.UserdefitemVO;
import nc.vo.ic.batchcode.BatchSynchronizer;
import nc.vo.ic.batchcode.ICBatchFields;
import nc.vo.ic.general.deal.ICBillValueSetter;
import nc.vo.ic.general.define.ICBillBodyVO;
import nc.vo.ic.general.define.ICBillVO;
import nc.vo.ic.general.define.MetaNameConst;
import nc.vo.ic.location.ICLocationVO;
import nc.vo.ic.material.define.InvBasAndCalInfo;
import nc.vo.ic.material.define.InvCalBodyVO;
import nc.vo.ic.material.define.InvMeasVO;
import nc.vo.ic.onhand.define.ICBillPickResults;
import nc.vo.ic.onhand.entity.OnhandDimVO;
import nc.vo.ic.pub.calc.BusiCalculator;
import nc.vo.ic.pub.define.ICPubMetaNameConst;
import nc.vo.ic.pub.lang.OnhandRes;
import nc.vo.ic.pub.util.CollectionUtils;
import nc.vo.ic.pub.util.NCBaseTypeUtils;
import nc.vo.ic.pub.util.StringUtil;
import nc.vo.ic.pub.util.VOEntityUtil;
import nc.vo.ic.pub.util.ValueCheckUtil;
import nc.vo.ic.sncode.ICSnFields;
import nc.vo.ic.sncode.ICSnForLocationFields;
import nc.vo.ic.sncode.SnCodeForLocationVOSynchronizer;
import nc.vo.ic.sncode.SnCodeSynchronizer;
import nc.vo.pub.BusinessException;
import nc.vo.pub.CircularlyAccessibleValueObject;
import nc.vo.pub.ISuperVO;
import nc.vo.pub.VOStatus;
import nc.vo.pub.lang.UFBoolean;
import nc.vo.pub.lang.UFDate;
import nc.vo.pub.lang.UFDouble;
import nc.vo.pubapp.AppContext;
import nc.vo.pubapp.pattern.data.IRowSet;
import nc.vo.pubapp.pattern.exception.ExceptionUtils;
import nc.vo.pubapp.pattern.pub.MapList;
import nc.vo.pubapp.pattern.pub.MathTool;
import nc.vo.pubapp.pattern.pub.SqlBuilder;
import nccloud.commons.collections.MapUtils;
import nccloud.dto.scmpub.pub.context.BillCardBodyChangedRow;
import nccloud.dto.scmpub.pub.context.BillCardBodyEditEvent;
import nccloud.pubimpl.ic.pub.operator.bodyafterrule.NumEventRule;
import nccloud.pubitf.ic.pub.service.IPickAutoService;

/**
 * 自动拣货
 *
 * @author hujieh
 *
 */
public class PickAutoServiceImpl implements IPickAutoService {

	Map<String, InvBasAndCalInfo> invInfoMap = new HashMap<String, InvBasAndCalInfo>();
	private Map<String, UFBoolean> isasunitstore;

	private BusiCalculator calc = BusiCalculator.getBusiCalculatorAtBS();

	@Override
	public Object autoPick(ICBillVO billvo, Map<String, Object> userObject) {
		List<ICBillBodyVO> delbodys = this.processDelBody(new ICBillVO[] { billvo });
		// 拣货前，先清除行备注，防止错误提示
		this.clearBodyNote(billvo);
		ICBillVO retBillvo = (ICBillVO) billvo.clone();
//		ICBillBodyVO[] bodyvos = retBillvo.getBodys();
		this.preprocess(retBillvo);
		OnhandResService resserver = NCLocator.getInstance().lookup(OnhandResService.class);
		try {

			// 预留处理
			ICBillVO[] retvos = NCLocator.getInstance().lookup(ReserveInOut.class)
					.reserveOutAutoPick(new ICBillVO[] { retBillvo }, false);
			retBillvo = retvos[0];
			ICBillBodyVO[] bodyvos = retvos[0].getBodys();
			// 支持预留拣货 modify by yangls7
//			ICBillPickResults results = resserver.reservePickAuto(billvo);
			ICBillPickResults results = resserver.pickAuto(retBillvo);
			if (results == null) {
				this.setBodyNoteOnhandErro(retBillvo.getBodys(), results);
				return retBillvo;
			}
			if (results.isResPick()) {
				fireNumEditEvent(retBillvo, ICPubMetaNameConst.NNUM, retBillvo.getBody(0).getNnum(), -1, userObject);
				return retBillvo;
			}
			// 查询物料基本信息和库存信息放到invInfoMap中
			this.loadInvCalBodyInfo(retBillvo);
			// 逐行遍历，如果这一行没捡到或就设置提示信息
//			this.setBodyNoteOnhandErro(retBillvo.getBodys(), results);
			// 处理是否辅计量结存，把物料是否勾选了辅单位是否计入结存记录下来
			this.getBAstunitStorebalance(retBillvo);
			// 同步序列号档案上信息到孙表
			this.fillSNDocToLocation(retBillvo, results);
			List<ICBillBodyVO> newBodyVOs = new ArrayList<ICBillBodyVO>();
			// 设置数据
			for (int i = 0; i < bodyvos.length; i++) {
				// 一行表体拣货后的行
				ICBillBodyVO[] bodys = results.getPickBodys(i);
				if (bodys == null || bodys.length <= 0) {
					// 如果此行没有拣货数据，将此行直接放入新表体中
					newBodyVOs.add(bodyvos[i]);
					// zhengxinm 次行没有拣货数据 可能在预留时已经拣货 可能拣货成功但是表体备注有问题 这里检查下 如果没问题清空表体备注 2020-11-04
					if ((bodyvos[i].getNassistnum() != null ? bodyvos[i].getNassistnum() : new UFDouble(0))
							.doubleValue() == (bodyvos[i].getNshouldassistnum() != null
									? bodyvos[i].getNshouldassistnum()
									: new UFDouble(0)).doubleValue()) {
						bodyvos[i].setVnotebody(null);
					}
					continue;
				}
				// 清空原始行号，用拣货结果设置行号，否则拆行后会行号重复
				bodyvos[i].setCrowno(null);
				// this.getEditorModel().getCardPanelWrapper().copyLine();
				List<ICBillBodyVO> rowBodyVOs = new ArrayList<ICBillBodyVO>();
				for (int k = 0; k < bodys.length; k++) {// 不知道这块之前为啥反向遍历 导致行号逆序 改过来了 zhengxinm 2021-03-10
					if (k == 0) {
						this.setOnhandDataToBody(bodys[k], bodyvos[i]);
						if (bodyvos[i].getStatus() != VOStatus.NEW) {
							bodyvos[i].setStatus(VOStatus.UPDATED);
						}
						rowBodyVOs.add(bodyvos[i]);
					} else {
						ICBillBodyVO tempBodyvo = (ICBillBodyVO) bodyvos[i].clone();
						this.processForNewVO(tempBodyvo);
						// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start
						if (k == bodys.length - 1) {
							this.setOnhandDataToBody_End(bodys[k], tempBodyvo, rowBodyVOs);
						} else {
							this.setOnhandDataToBody(bodys[k], tempBodyvo);
						}
						rowBodyVOs.add(tempBodyvo);
						// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start

					}
				}
				newBodyVOs.addAll(rowBodyVOs);
			}
			// 查询出来的对应入库单交易类型为编码，需要转换成主键再走模板翻译
			this.translateCcorres(newBodyVOs);
			retBillvo.setChildren(bodyvos[0].getClass(), CollectionUtils.listToArray(newBodyVOs));
			this.setbodyNote(retBillvo, results);
			// 同步表体批次辅助字段
			new BatchSynchronizer(new ICBatchFields()).fillBatchVOtoBill(retBillvo.getBodys());
			// 处理供应商 客户vid字段
			fireCvendoridEvent(retBillvo.getBodys());

			// 同步表体序列号辅助字段
			new SnCodeSynchronizer(new ICSnFields()).fillBatchVOtoBill(retBillvo.getBodys());
			fireNumEditEvent(retBillvo, ICPubMetaNameConst.NNUM, newBodyVOs.get(0).getNnum(), -1, userObject);

		} catch (BusinessException e) {
			ExceptionUtils.wrappBusinessException(e.getMessage());
		}
		CircularlyAccessibleValueObject[] allChildrenVO = retBillvo.getAllChildrenVO();
		CollectionUtils.addArrayToList(delbodys, (ICBillBodyVO[]) allChildrenVO);
		retBillvo.setChildrenVO(CollectionUtils.listToArray(delbodys));
		return retBillvo;
	}

	private void setOnhandDataToBody_End(ICBillBodyVO bodyvo, ICBillBodyVO origin, List<ICBillBodyVO> newBodyVOs) {
		if (bodyvo == null) {
			return;
		}
		// 表体主键复制，防止拣货拆行后，主键重复
//		origin
//				.setAttributeValue(MetaNameConst.CGENERALBID, bodyvo.getCgeneralbid());
		// 行号设置，已经清空原始行号，用拣货结果设置
		origin.setAttributeValue(ICPubMetaNameConst.CROWNO, bodyvo.getCrowno());
		this.processOnhandDimInfo(bodyvo, origin);
		// 货位管理仓，货位信息单独处理
		this.resetBodyLocationID(bodyvo, origin);
		this.processCcorrespondInfo(bodyvo, origin);

		this.processNumInfo_End(bodyvo, origin, newBodyVOs);
		this.setSNInfoToBody(bodyvo, origin);
	}

	private void processNumInfo_End(ICBillBodyVO bodyvo, ICBillBodyVO origin, List<ICBillBodyVO> newBodyVOs) {
		origin.setAttributeValue(ICPubMetaNameConst.NNUM, bodyvo.getNnum());
		origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
		origin.setAttributeValue(ICPubMetaNameConst.NGROSSNUM, bodyvo.getNgrossnum());
		// 计算前几行的应发数量合
		UFDouble sumShouldNum = UFDouble.ZERO_DBL;
		UFDouble sumShouldAssistNum = UFDouble.ZERO_DBL;
		for (ICBillBodyVO bodyVO : newBodyVOs) {
			UFDouble nShouldnum = bodyVO.getNshouldnum();
			UFDouble nShouldAssistNum = bodyVO.getNshouldassistnum();
			sumShouldNum = MathTool.add(sumShouldNum, nShouldnum);
			sumShouldAssistNum = MathTool.add(sumShouldAssistNum, nShouldAssistNum);
		}
		// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start
		origin.setAttributeValue(ICPubMetaNameConst.NSHOULDNUM, MathTool.sub(bodyvo.getNshouldnum(), sumShouldNum));
		origin.setAttributeValue(ICPubMetaNameConst.NSHOULDASSISTNUM,
				MathTool.sub(bodyvo.getNshouldassistnum(), sumShouldAssistNum));
		// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start

		UFDouble shouldnum = origin.getNshouldnum();
		UFDouble shouldastnum = origin.getNshouldassistnum();
		UFDouble num = origin.getNnum();
		if (NCBaseTypeUtils.isNullOrZero(shouldnum) && NCBaseTypeUtils.isNullOrZero(shouldastnum)
				&& NCBaseTypeUtils.isNullOrZero(num)) {
			return;
		}

		InvCalBodyVO calbodyvo = invInfoMap.get(origin.getCmaterialvid()).getInvcalbodyvo();

		// 清空辅数量，避免辅数量是拣货前数量，影响联动计算
		origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, null);
		// v636版本 单品管理的处理改变
		if (ValueCheckUtil.isTrue(calbodyvo.getSerialmanaflag())) {
			origin.setAttributeValue(ICPubMetaNameConst.NNUM, bodyvo.getNnum());
//			this.caculateAfterNumEdit(bodyvo);
			origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
			boolean isNullServialcode = StringUtil.isSEmptyOrNullForAll(
					VOEntityUtil.getVOsValuesNotDel(bodyvo.getLocationVOs(), ICLocationVO.VSERIALCODE, String.class));
			if (bodyvo.getLocationVOs() != null && isNullServialcode) {
				this.processLocAstNum(bodyvo);
			}
//			origin.setLocationVOs(bodyvo.getLocationVOs());
			ICLocationVO[] lvos = origin.getLocationVOs();
			ICLocationVO[] lvos2 = bodyvo.getLocationVOs();
			if (lvos2 != null) {
				// 这里获取的pks可能是[null,null,...] 这样的 增加过滤
				String[] lpks = VOEntityUtil.getVOsValuesNotDel(lvos == null ? new ICLocationVO[] {} : lvos,
						ICLocationVO.PK_SERIALCODE, String.class);
				List<String> lpkList = new ArrayList<String>();
				if (lpks != null && lpks.length > 0) {
					for (String lpk : lpks) {
						if (lpk != null) {
							lpkList.add(lpk);
						}
					}
				}

				// 这里获取的pks可能是[null,null,...] 这样的 增加过滤

				if (lpkList.size() > 0) {
					int needNum = shouldnum.intValue();

					for (ICLocationVO lvo : lvos2) {
						if (!lpkList.contains(lvo.getPk_serialcode()) && lvos.length < needNum) {
							lvos = CollectionUtils.combineArrs(lvos, new ICLocationVO[] { lvo });
//							needNum--;
						}
					}
				} else {
					lvos = CollectionUtils.combineArrs(lvos, lvos2);
				}
			}
			origin.setLocationVOs(lvos);
			return;
		}

//		this.caculateAfterNumEdit(bodyvo);
		// 对于辅计量记结存的物料，计算辅数量之后，会导致界面展示和结存数据不一致，所以用结存数据设置
		if (!ValueCheckUtil.isNullORZeroLength(this.isasunitstore)) {
			if (ValueCheckUtil
					.isTrue(this.isasunitstore.get((String) origin.getAttributeValue(ICPubMetaNameConst.CMATERIALVID)
							+ (String) origin.getAttributeValue(ICPubMetaNameConst.CASTUNITID)))) {
				origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
			} else {
				bodyvo.setNassistnum(calc.calculateAstNum(bodyvo.getNnum(),
						(String) origin.getAttributeValue(ICPubMetaNameConst.VCHANGERATE), bodyvo.getCasscustid()));
			}
		}

		if (bodyvo.getLocationVOs() != null) {
			this.processLocAstNum(bodyvo);
			origin.setLocationVOs(bodyvo.getLocationVOs());
		}
	}

	/**
	 * 查询出来的对应入库单交易类型为编码，需要转换成主键再走模板翻译
	 * 
	 * @param newBodyVOs
	 */
	private void translateCcorres(List<ICBillBodyVO> newBodyVOs) {
		Set<String> codeSet = new HashSet<String>();
		if (newBodyVOs != null && newBodyVOs.size() > 0) {
			for (ICBillBodyVO bodyVO : newBodyVOs) {
				codeSet.add(bodyVO.getCcorrespondtranstype());
			}
		}
		Map<String, String> idMap = new HashMap<String, String>();
		if (codeSet.size() > 0) {
			String pk_group = InvocationInfoProxy.getInstance().getGroupId();
			SqlBuilder sql = new SqlBuilder();
			sql.append(" select pk_billtypecode, pk_billtypeid from bd_billtype where ");
			sql.append(" pk_group ", pk_group);
			sql.append(" and ");
			sql.append(" pk_billtypecode ", codeSet.toArray(new String[codeSet.size()]));
			IRowSet query = new DataAccessUtils().query(sql.toString());
			while (query.next()) {
				idMap.put(query.getString(0), query.getString(1));
			}
		}
		if (MapUtils.isNotEmpty(idMap)) {
			for (ICBillBodyVO bodyVO : newBodyVOs) {
				bodyVO.setCcorrespondtranstype(idMap.get(bodyVO.getCcorrespondtranstype()));
			}
		}
	}

	private void fireCvendoridEvent(ICBillBodyVO[] bodys) {
		if (bodys == null || bodys.length == 0) {
			return;
		}
		HashSet<String> cvendoridset = new HashSet<String>();
		HashSet<String> casscustidset = new HashSet<String>();
		// 货主客户
		HashSet<String> ctplcustomeridset = new HashSet<String>();
		// 寄存供应商
		HashSet<String> cvmivenderidset = new HashSet<String>();
		for (ICBillBodyVO body : bodys) {
			String cvendorid = body.getCvendorid();
			String casscustid = body.getCasscustid();
			String ctplcustomerid = body.getCtplcustomerid();
			String cvmivenderid = body.getCvmivenderid();
			if (cvendorid != null) {
				cvendoridset.add(cvendorid);
			}
			if (casscustid != null) {
				casscustidset.add(casscustid);
			}
			if (ctplcustomerid != null) {
				ctplcustomeridset.add(ctplcustomerid);
			}
			if (cvmivenderid != null) {
				cvmivenderidset.add(cvmivenderid);
			}
		}
		// 获取所有表体的供应商oid 拣货后台逻辑未变只带出物料辅助属性的客户 供应商oid 补充vid
		HashMap<String, String> cvendoridMap = new HashMap<String, String>();
		HashMap<String, String> casscustidMap = new HashMap<String, String>();
		HashMap<String, UFDate> cvendoridAndDate = new HashMap<String, UFDate>();
		HashMap<String, UFDate> casscustidAndDate = new HashMap<String, UFDate>();
		HashMap<String, String> ctplcustomeridMap = new HashMap<String, String>();
		HashMap<String, String> cvmivenderidMap = new HashMap<String, String>();
		HashMap<String, UFDate> ctplcustomeridAndDate = new HashMap<String, UFDate>();
		HashMap<String, UFDate> cvmivenderidAndDate = new HashMap<String, UFDate>();
		UFDate busidate = AppContext.getInstance().getBusiDate();
		if (cvendoridset != null && cvendoridset.size() > 0) {
			for (String cvendorid : cvendoridset) {
				cvendoridAndDate.put(cvendorid, busidate);
			}
			// 根据供应商oid和业务日期查询vid
			cvendoridMap = (HashMap<String, String>) SupplierPubService.querySupplierVidsByOidAndDate(cvendoridAndDate);
		}
		if (casscustidset != null && casscustidset.size() > 0) {
			for (String casscustid : casscustidset) {
				casscustidAndDate.put(casscustid, busidate);
			}
			// 根据客户oid和业务日期查询vid
			casscustidMap = (HashMap<String, String>) CustomerPubService
					.queryCustomerVidsByOidsAndDate(casscustidAndDate);
		}
		if (ctplcustomeridset != null && ctplcustomeridset.size() > 0) {
			for (String ctplcustomerid : ctplcustomeridset) {
				ctplcustomeridAndDate.put(ctplcustomerid, busidate);
			}
			// 根据货主客户oid和业务日期查询vid
			ctplcustomeridMap = (HashMap<String, String>) CustomerPubService
					.queryCustomerVidsByOidsAndDate(ctplcustomeridAndDate);
		}
		if (cvmivenderidset != null && cvmivenderidset.size() > 0) {
			for (String cvmivenderid : cvmivenderidset) {
				cvmivenderidAndDate.put(cvmivenderid, busidate);
			}
			// 根据寄存供应商oid和业务日期查询vid
			cvmivenderidMap = (HashMap<String, String>) SupplierPubService
					.querySupplierVidsByOidAndDate(cvmivenderidAndDate);
		}
		// 根据客户 供应商oid对vid赋值
		for (ICBillBodyVO body : bodys) {
			if (body.getCvendorid() != null) {
				body.setCvendorvid(cvendoridMap.get(body.getCvendorid()));
			}
			if (body.getCasscustid() != null) {
				body.setCasscustvid(casscustidMap.get(body.getCasscustid()));
			}
			if (body.getCtplcustomerid() != null) {
				body.setCtplcustomervid(ctplcustomeridMap.get(body.getCtplcustomerid()));
			}
			if (body.getCvmivenderid() != null) {
				body.setCvmivendervid(cvmivenderidMap.get(body.getCvmivenderid()));
			}
		}
	}

	private List<ICBillBodyVO> processDelBody(ICBillVO[] vos) {
		ICBillBodyVO[] bodys = vos[0].getBodys();
		List<ICBillBodyVO> realbody = new ArrayList<ICBillBodyVO>();
		List<ICBillBodyVO> delbodys = new ArrayList<ICBillBodyVO>();
		for (ICBillBodyVO body : bodys) {
			if (body.getStatus() != 3) {
				realbody.add(body);
			} else {
				delbodys.add(body);
			}
		}
		vos[0].setChildrenVO(null);
		vos[0].setChildrenVO(CollectionUtils.listToArray(realbody));
		return delbodys;
	}

	/**
	 * 主数量编辑后处理
	 *
	 * @param row
	 * @param newnum
	 * @param oldnum
	 */
	private void fireNumEditEvent(ICBillVO billvo, String numField, UFDouble num, int index,
			Map<String, Object> userObject) {
		// 获取拣货后的billvo的实发数量存放到数量编辑后事件之后的新vo里
		Map<String, UFDouble> nassistnumMap = new HashMap<>();
		Map<String, UFDouble> nnumMap = new HashMap<>();
		CircularlyAccessibleValueObject[] bodys = billvo.getAllChildrenVO();
		int i = 0;
		for (CircularlyAccessibleValueObject body : bodys) {
			UFDouble nassistnum = (UFDouble) body.getAttributeValue(MetaNameConst.NASSISTNUM);
			UFDouble nnum = (UFDouble) body.getAttributeValue(MetaNameConst.NNUM);
			String crowno = (String) body.getAttributeValue(MetaNameConst.CROWNO);
			if (crowno == null) {
				i = i + 10;
				crowno = i + "";
				body.setAttributeValue(MetaNameConst.CROWNO, crowno);
			}
			nassistnumMap.put(crowno, nassistnum);
			nnumMap.put(crowno, nnum);
		}

		BillCardBodyChangedRow changedRow = new BillCardBodyChangedRow(num, null, null);
		BillCardBodyEditEvent event = new BillCardBodyEditEvent(numField, index,
				new BillCardBodyChangedRow[] { changedRow }, null);
		new NumEventRule().afterEdit(billvo, event, userObject);

		CircularlyAccessibleValueObject[] newBodys = billvo.getAllChildrenVO();
		for (CircularlyAccessibleValueObject body : newBodys) {
			if (nassistnumMap.get(body.getAttributeValue(MetaNameConst.CROWNO)) != null) {
				body.setAttributeValue(MetaNameConst.NASSISTNUM,
						nassistnumMap.get(body.getAttributeValue(MetaNameConst.CROWNO)));
			}
			if (nnumMap.get(body.getAttributeValue(MetaNameConst.CROWNO)) != null) {
				body.setAttributeValue(MetaNameConst.NNUM, nnumMap.get(body.getAttributeValue(MetaNameConst.CROWNO)));
			}
		}
	}

	/**
	 * 拣货结果不满足应发数量的备注设置成“现存量不足” 分批的场景，只设置第一行。 方法功能描述：
	 * <p>
	 * <b>参数说明</b>
	 *
	 * @param bodys
	 *              <p>
	 * @since 6.3
	 * @author zhaofeid
	 * @time 2013-7-31 下午04:45:39
	 */
	private void setbodyNote(ICBillVO billvo, ICBillPickResults results) {
		ICBillBodyVO[] uiBodys = billvo.getBodys();
		String errMsg = OnhandRes.getOnhandErro();
		Set<String> origRowNo = new HashSet<String>();

		int realIndex = 0;
		int pickIndex = 1;// 拣货下标
		for (int i = 0, loop = uiBodys.length; i < loop; i++) {
			if (uiBodys[i].getNshouldassistnum() == null && uiBodys[i].getNshouldnum() == null) {
				continue;
			}

			ICBillBodyVO[] bodys = results.getPickBodys(realIndex);
			if (ValueCheckUtil.isNullORZeroLength(bodys)) {
				continue;
			}

			ICBillBodyVO uibody = uiBodys[i];
			UFDouble nshouldnum = uibody.getNshouldnum();
			String crowno = uibody.getCrowno();
			for (ICBillBodyVO body : bodys) {
				// 防止多次计算，添加货位判断，同一行表体拣货拆分行后，表体行和拣货行货位相同--sdlizheng start
				if (body.getClocationid() == null || body.getClocationid().equals(uibody.getClocationid())) {
					UFDouble nnum = body.getNnum();
					nshouldnum = nshouldnum.sub(nnum);
				}
				// 防止多次计算，添加货位判断，同一行表体拣货拆分行后，表体行和拣货行货位相同--sdlizheng start
			}

			if (nshouldnum != null && UFDouble.ZERO_DBL.compareTo(nshouldnum) < 0) {
				origRowNo.add(crowno);
			}
			// sdlizheng --因为拣货拆行，获取pickbodys时的下标row需要循环完此次已拣货的行数之后加1--start
			if (pickIndex == bodys.length) {
				realIndex++;
				pickIndex = 1;
			} else {
				pickIndex++;
			}
			// sdlizheng --因为拣货拆行，获取pickbodys时的下标row需要循环完此次已拣货的行数之后加1--end
		}
		for (int i = 0; i < uiBodys.length; i++) {
			String rowno = (String) uiBodys[i].getAttributeValue(ICPubMetaNameConst.CROWNO);
			if (origRowNo.contains(rowno)) {
				uiBodys[i].setAttributeValue(ICPubMetaNameConst.VNOTEBODY, errMsg);
			}
		}
	}

	private void processForNewVO(ICBillBodyVO tempBodyvo) {
		// 由于粘贴行会把复制行的报价数量带过来，导致浮动换算率时计算报价换算率错误
		tempBodyvo.setAttributeValue(MetaNameConst.NQTUNITNUM, null);
		tempBodyvo.setAttributeValue(ICPubMetaNameConst.NSHOULDNUM, null);
		tempBodyvo.setAttributeValue(ICPubMetaNameConst.NSHOULDASSISTNUM, null);
		tempBodyvo.setAttributeValue(ICPubMetaNameConst.NNUM, null);
		tempBodyvo.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, null);
		tempBodyvo.setAttributeValue(MetaNameConst.CGENERALBID, null);
		tempBodyvo.setLocationVOs(null);
		tempBodyvo.setAttributeValue("rowid", null);
		tempBodyvo.setStatus(VOStatus.NEW);

		// 清除扩展表数据
		clearExtendTableData(tempBodyvo);
	}

	private void clearExtendTableData(ICBillBodyVO tempBodyvo) {
		String[] extendTableField = new String[] { "naccumvminum", "ncorrespondgrsnum", "ncorrespondastnum",
				"ncorrespondnum", "naccumoutsignnum", "naccumoutbacknum", "nrushnum", "nsignnum", "ntotaltrannum",
				"btranendflag", "naccumwastnum", "csumid" };
		for (String field : extendTableField) {
			tempBodyvo.setAttributeValue(field, null);
		}
	}

	private void setOnhandDataToBody(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		if (bodyvo == null) {
			return;
		}
		// 表体主键复制，防止拣货拆行后，主键重复
//		origin
//				.setAttributeValue(MetaNameConst.CGENERALBID, bodyvo.getCgeneralbid());
		// 行号设置，已经清空原始行号，用拣货结果设置
		origin.setAttributeValue(ICPubMetaNameConst.CROWNO, bodyvo.getCrowno());
		this.processOnhandDimInfo(bodyvo, origin);
		// 货位管理仓，货位信息单独处理
		this.resetBodyLocationID(bodyvo, origin);
		this.processCcorrespondInfo(bodyvo, origin);

		this.processNumInfo(bodyvo, origin);
		this.setSNInfoToBody(bodyvo, origin);
	}

	private void setSNInfoToBody(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		// 处理表体序列号
		if (!SysInitGroupQuery.isSNEnabled()) {
			return;
		}
		UFDouble nassistnum = (UFDouble) origin.getAttributeValue(ICPubMetaNameConst.NASSISTNUM);
		// 只有表体数量为1时才设置表体值
		if (!NCBaseTypeUtils.isEquals(nassistnum, UFDouble.ONE_DBL)) {
			return;
		}
		ICLocationVO[] lvoes = origin.getLocationVOs();
		// 因为捡完第一次货删了实发数量重新拣货之后，孙表虽然不是一个，但没被删除的只有一个
		if (lvoes != null && lvoes.length > 0) {
			List<ICLocationVO> lvoLists = new ArrayList<>();
			for (ICLocationVO lvo : lvoes) {
				if (VOStatus.DELETED != lvo.getStatus()) {
					lvoLists.add(lvo);
				}
			}
			ICLocationVO[] lvos = lvoLists.toArray(new ICLocationVO[] {});
			if (ValueCheckUtil.isNullORZeroLength(lvos) || lvos.length != 1) {
				return;
			}
			ICLocationVO lvo = lvos[0];
			if (StringUtil.isNullStringOrNull(lvo.getVserialcode())
					&& StringUtil.isNullStringOrNull(lvo.getPk_serialcode())) {
				return;
			}
			origin.setAttributeValue(ICPubMetaNameConst.VSERIALCODE, lvos[0].getVserialcode());
			origin.setAttributeValue(ICPubMetaNameConst.PK_SERIALCODE, lvos[0].getPk_serialcode());
		}
	}

	private void processNumInfo(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		origin.setAttributeValue(ICPubMetaNameConst.NNUM, bodyvo.getNnum());
		origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
		origin.setAttributeValue(ICPubMetaNameConst.NGROSSNUM, bodyvo.getNgrossnum());
		// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start
		origin.setAttributeValue(ICPubMetaNameConst.NSHOULDNUM, bodyvo.getNnum());
		origin.setAttributeValue(ICPubMetaNameConst.NSHOULDASSISTNUM, bodyvo.getNassistnum());
		// 78--2025年4月9日19点11分--sdlizheng--实发传输到应发，最后一行做合计处理--start

		UFDouble shouldnum = origin.getNshouldnum();
		UFDouble shouldastnum = origin.getNshouldassistnum();
		UFDouble num = origin.getNnum();
		if (NCBaseTypeUtils.isNullOrZero(shouldnum) && NCBaseTypeUtils.isNullOrZero(shouldastnum)
				&& NCBaseTypeUtils.isNullOrZero(num)) {
			return;
		}

		InvCalBodyVO calbodyvo = invInfoMap.get(origin.getCmaterialvid()).getInvcalbodyvo();

		// 清空辅数量，避免辅数量是拣货前数量，影响联动计算
		origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, null);
		// v636版本 单品管理的处理改变
		if (ValueCheckUtil.isTrue(calbodyvo.getSerialmanaflag())) {
			origin.setAttributeValue(ICPubMetaNameConst.NNUM, bodyvo.getNnum());
//			this.caculateAfterNumEdit(bodyvo);
			origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
			boolean isNullServialcode = StringUtil.isSEmptyOrNullForAll(
					VOEntityUtil.getVOsValuesNotDel(bodyvo.getLocationVOs(), ICLocationVO.VSERIALCODE, String.class));
			if (bodyvo.getLocationVOs() != null && isNullServialcode) {
				this.processLocAstNum(bodyvo);
			}
//			origin.setLocationVOs(bodyvo.getLocationVOs());
			ICLocationVO[] lvos = origin.getLocationVOs();
			ICLocationVO[] lvos2 = bodyvo.getLocationVOs();
			if (lvos2 != null) {
				// 这里获取的pks可能是[null,null,...] 这样的 增加过滤
				String[] lpks = VOEntityUtil.getVOsValuesNotDel(lvos == null ? new ICLocationVO[] {} : lvos,
						ICLocationVO.PK_SERIALCODE, String.class);
				List<String> lpkList = new ArrayList<String>();
				if (lpks != null && lpks.length > 0) {
					for (String lpk : lpks) {
						if (lpk != null) {
							lpkList.add(lpk);
						}
					}
				}

				// 这里获取的pks可能是[null,null,...] 这样的 增加过滤

				if (lpkList.size() > 0) {
					int needNum = shouldnum.intValue();

					for (ICLocationVO lvo : lvos2) {
						if (!lpkList.contains(lvo.getPk_serialcode()) && lvos.length < needNum) {
							lvos = CollectionUtils.combineArrs(lvos, new ICLocationVO[] { lvo });
//							needNum--;
						}
					}
				} else {
					lvos = CollectionUtils.combineArrs(lvos, lvos2);
				}
			}
			origin.setLocationVOs(lvos);
			return;
		}

//		this.caculateAfterNumEdit(bodyvo);
		// 对于辅计量记结存的物料，计算辅数量之后，会导致界面展示和结存数据不一致，所以用结存数据设置
		if (!ValueCheckUtil.isNullORZeroLength(this.isasunitstore)) {
			if (ValueCheckUtil
					.isTrue(this.isasunitstore.get((String) origin.getAttributeValue(ICPubMetaNameConst.CMATERIALVID)
							+ (String) origin.getAttributeValue(ICPubMetaNameConst.CASTUNITID)))) {
				origin.setAttributeValue(ICPubMetaNameConst.NASSISTNUM, bodyvo.getNassistnum());
			} else {
				bodyvo.setNassistnum(calc.calculateAstNum(bodyvo.getNnum(),
						(String) origin.getAttributeValue(ICPubMetaNameConst.VCHANGERATE), bodyvo.getCasscustid()));
			}
		}

		if (bodyvo.getLocationVOs() != null) {
			this.processLocAstNum(bodyvo);
			origin.setLocationVOs(bodyvo.getLocationVOs());
		}
	}

	/**
	 * 处理货位信息的辅数量，进行重新计算，并处理尾差，解决存量不足时货位单品信息数量错误的问题。
	 *
	 * @param body
	 * @param cal
	 */
	private void processLocAstNum(ICBillBodyVO body) {
		ICLocationVO[] locs = body.getLocationVOs();
		if (ValueCheckUtil.isNullORZeroLength(locs)) {
			return;
		}

		UFDouble bodynum = body.getNassistnum();
		UFDouble nsum = UFDouble.ZERO_DBL;
		UFDouble nassistnum = UFDouble.ZERO_DBL;
		for (int i = 0; i < locs.length - 1; i++) {
			// 此处无论是否单品管理，都需要处理辅数量，否则有货位信息时，更新存量会有问题
			nassistnum = calc.calculateAstNum(locs[i].getNnum(), body.getVchangerate(), body.getCastunitid());

			locs[i].setNassistnum(nassistnum);
			nsum = NCBaseTypeUtils.add(nsum, nassistnum);
		}
		if (locs.length != 1) {
			locs[locs.length - 1].setNassistnum(NCBaseTypeUtils.sub(bodynum, nsum));
		} else if (locs.length == 1) {
			locs[0].setNassistnum(bodynum);
		}
	}

	private void processCcorrespondInfo(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		String[] corresponds = new String[] { MetaNameConst.CCORRESPONDTYPE, MetaNameConst.CCORRESPONDTRANSTYPE,
				MetaNameConst.CCORRESPONDCODE, MetaNameConst.CCORRESPONDHID, MetaNameConst.CCORRESPONDBID,
				MetaNameConst.CCORRESPONDROWNO, ICPubMetaNameConst.CROWNO, ICPubMetaNameConst.NCOSTMNY,
				ICPubMetaNameConst.NPLANNEDMNY, MetaNameConst.DBIZDATE, ICPubMetaNameConst.VNOTEBODY };
		String cmateiralvid = (String) origin.getAttributeValue(ICPubMetaNameConst.CMATERIALVID);
		InvCalBodyVO invvo = this.invInfoMap.get(cmateiralvid).getInvcalbodyvo();
		// 对于非出入库跟踪物料，不处理对应入库单信息，否则会把原始信息清掉（出库参照入库单拉单）
		if (invvo == null || !ValueCheckUtil.isTrue(invvo.getOuttrackin())) {
			return;
		}
		for (String field : corresponds) {
			origin.setAttributeValue(field, bodyvo.getAttributeValue(field));
		}
	}

	/**
	 * 重新设置表体货位ID，如果单品信息分布在多个货位，清空表体，否则，设置单品货位信息到表体
	 *
	 * @param bodyvo拣货结果
	 * @param row        当前行
	 */
	private void resetBodyLocationID(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		ICLocationVO[] locs = bodyvo.getLocationVOs();

		if (ValueCheckUtil.isNullORZeroLength(locs)) {
			return;
		}

		List<String> locids = VOEntityUtil.getVOsValueListNotDel(locs, ICLocationVO.CLOCATIONID);
		if (ValueCheckUtil.isNullORZeroLength(locids)) {
			return;
		}

		String locid = locids.get(0);
		for (String id : locids) {
			if (!StringUtil.isStringEqual(locid, id)) {
				locid = null;
				break;
			}
		}
		origin.setAttributeValue(ICPubMetaNameConst.CLOCATIONID, locid);
	}

	private void processOnhandDimInfo(ICBillBodyVO bodyvo, ICBillBodyVO origin) {
		for (String field : OnhandDimVO.getDimContentFields()) {
			if (field.equals(OnhandDimVO.VBATCHCODE)) {
				origin.setAttributeValue(field, bodyvo.getAttributeValue(field));
				continue;
			}
			if (field.equals(OnhandDimVO.CLOCATIONID)) {
				// V60，货位管理仓，货位信息单独处理
				continue;
			}
			// 拣出的货非换算率记结存场合，不包含换算率信息
			if (field.equals(OnhandDimVO.VCHANGERATE) && StringUtil.isSEmptyOrNull(bodyvo.getVchangerate())) {
				continue;
			}
			// 固定辅助属性(库存状态、项目、供应商、生产厂商、客户)
			if (field.equals(OnhandDimVO.CSTATEID) && StringUtil.isSEmptyOrNull(bodyvo.getCstateid())) {
				continue;
			}
			if (field.equals(OnhandDimVO.CPROJECTID) && StringUtil.isSEmptyOrNull(bodyvo.getCprojectid())) {
				continue;
			}
			if (field.equals(OnhandDimVO.CVENDORID) && StringUtil.isSEmptyOrNull(bodyvo.getCvendorid())) {
				continue;
			}
			if (field.equals(OnhandDimVO.CPRODUCTORID) && StringUtil.isSEmptyOrNull(bodyvo.getCproductorid())) {
				continue;
			}
			if (field.equals(OnhandDimVO.CASSCUSTID) && StringUtil.isSEmptyOrNull(bodyvo.getCasscustid())) {
				continue;
			}
			if (field.equals(OnhandDimVO.CFFILEID) && StringUtil.isSEmptyOrNull(bodyvo.getCffileid())) {
				continue;
			}
			origin.setAttributeValue(field, bodyvo.getAttributeValue(field));
		}
	}

	/**
	 * 拣货之前，清除旧的备注
	 *
	 * @param uiBodys
	 */
	private void clearBodyNote(ICBillVO billvo) {
		ICBillBodyVO[] bodyvos = billvo.getBodys();
		for (int i = 0; i < bodyvos.length; i++) {
			bodyvos[i].setAttributeValue(ICPubMetaNameConst.NNUM, null);
			bodyvos[i].setAttributeValue(ICPubMetaNameConst.NASSISTNUM, null);
//			String vnote = (String) bodyvos[i]
//					.getAttributeValue(ICPubMetaNameConst.VNOTEBODY);
//			if (StringUtil.isSEmptyOrNull(vnote)
//					|| vnote.indexOf(OnhandRes.getOnhandErro()) < 0) {
//				continue;
//			}
			bodyvos[i].setAttributeValue(ICPubMetaNameConst.VNOTEBODY, null);
		}
	}

	/**
	 * 拣货前预处理：清空实发数量、清空表体备注、格式化记结存的变动换算率
	 */
	private void preprocess(ICBillVO billvo) {
		// 清空单据表体数据
//		for (ICBillBodyVO body : billvo.getBodys()) {
//			ICLocationVO[] locationVOs = body.getLocationVOs();
//			if(locationVOs != null) {
//				for (ICLocationVO icLocationVO : locationVOs) {
//					icLocationVO.setStatus(3);
//				}
//			}
//			body.setLocationVOs(locationVOs);
//		}
		IMarAssistantPubService assistantPubService = NCLocator.getInstance().lookup(IMarAssistantPubService.class);
		try {
			UserdefitemVO[] userdefitemVOs = assistantPubService
					.queryMarAssistantDefine(AppContext.getInstance().getPkGroup());
			boolean isUseDef = false;
			if (userdefitemVOs != null) {
				for (UserdefitemVO vo : userdefitemVOs) {
					if (vo.getClassid().equals("BS000010000100001032")) {
						isUseDef = true;
					}
				}
			}
			if (isUseDef) {
				this.processFreeDef(billvo);
			}
		} catch (BusinessException e) {
			ExceptionUtils.wrappException(e);
		}
		// 统一处理变动换算率格式，否则与结存的换算率格式不匹配
		new ICBillValueSetter().procChangeRateFormat(new ICBillVO[] { billvo }, new ICBSContext().getInvInfo());
	}

	/**
	 * 拣货前处理 物料启用了布尔类型自由辅助属性 导致存量维度不匹配
	 */
	@SuppressWarnings("unchecked")
	private void processFreeDef(ICBillVO billvo) {
		Class<? extends ISuperVO> clazz = (Class<? extends ISuperVO>) billvo.getClass();
		MapList<String, String> checkvalue = check(ICPubMetaNameConst.CMATERIALVID, billvo.getChildren(clazz));
		for (ICBillBodyVO bodyvo : billvo.getBodys()) {
			if (checkvalue == null) {
				for (int k = 1; k <= 10; k++) {
					String index = "vfree" + k;
					Object vfree = bodyvo.getAttributeValue(index);
					if ((vfree != null && vfree.equals("N"))) {
						bodyvo.setAttributeValue(index, null);
					}
				}
			} else {
				Map<String, List<String>> maplist = checkvalue.toMap();
				List<String> list = maplist.get(bodyvo.getAttributeValue(ICPubMetaNameConst.CMATERIALVID));
				for (int k = 1; k <= 10; k++) {
					String index = "vfree" + k;
					Object vfree = bodyvo.getAttributeValue(index);
					if ((vfree != null && vfree.equals("N"))) {
						if (list == null || !list.contains(index)) {
							bodyvo.setAttributeValue(index, null);
						}
					}
				}
			}
		}
	}

	public MapList<String, String> check(String materialField, ISuperVO[] valueObjects) {
		MapList<String, String> materialMapList = new MapList<String, String>();
		Map<String, MaterialVO> materialMap = this.getMaterialMap(materialField, valueObjects);
		if (materialMap == null || materialMap.size() == 0) {
			return null;
		}
		Map<String, List<Integer>> marFrameMap = this.getMarFrameMap(materialMap);
		if (marFrameMap == null || marFrameMap.size() == 0) {
			return null;
		}
		for (ISuperVO value : valueObjects) {
			Object pk_material = value.getAttributeValue(materialField);
			String pk_marasstframe = materialMap.get(pk_material).getPk_marasstframe();
			List<Integer> list = marFrameMap.get(pk_marasstframe);
			if (list == null) {
				continue;
			}
			for (Integer listvlaue : list) {
				if (pk_marasstframe != null) {
					materialMapList.put(pk_material.toString(), "vfree" + (listvlaue - 5));
				}
			}
		}
		return materialMapList;
	}

	private Map<String, List<Integer>> getMarFrameMap(Map<String, MaterialVO> materialMap) {
		Map<String, List<Integer>> marFrameMap = null;
		try {
			Set<String> marFramePkSet = new HashSet<String>();
			for (Entry<String, MaterialVO> entry : materialMap.entrySet()) {
				String pk_marasstframe = entry.getValue().getPk_marasstframe();
				if (pk_marasstframe != null) {
					marFramePkSet.add(pk_marasstframe);
				}
			}
			marFrameMap = MarAssistantCheckUtils
					.queryMarAsstFrameIncludeDefPropIndex(marFramePkSet.toArray(new String[0]));
		} catch (BusinessException e) {
			ExceptionUtils.wrappException(e);
		}
		return marFrameMap;
	}

	private Map<String, MaterialVO> getMaterialMap(String materialField, ISuperVO[] valueObjects) {
		Map<String, MaterialVO> materialMap = null;
		try {
			Set<String> marPkSet = new HashSet<String>();
			for (int i = 0; i < valueObjects.length; i++) {
				String pk_material = (String) valueObjects[i].getAttributeValue(materialField);
				marPkSet.add(pk_material);
			}

			IMaterialPubService_C marService = NCLocator.getInstance().lookup(IMaterialPubService_C.class);
			materialMap = marService.queryMaterialBaseInfoByPks(marPkSet.toArray(new String[0]),
					new String[] { MaterialVO.PK_MARASSTFRAME, MaterialVO.NAME, MaterialVO.NAME2, MaterialVO.NAME3,
							MaterialVO.NAME4, MaterialVO.NAME5, MaterialVO.NAME6 });
		} catch (BusinessException e) {
			ExceptionUtils.wrappException(e);
		}
		return materialMap;
	}

	/**
	 * 没有拣到存量的行，设置表体备注“现存量不足”
	 *
	 * @param uiBodys
	 * @param results
	 */
	private void setBodyNoteOnhandErro(ICBillBodyVO[] uiBodys, ICBillPickResults results) {
		String errMsg = OnhandRes.getOnhandErro();
		if (results == null) {
			for (int i = 0, loop = uiBodys.length; i < loop; i++) {

				if (null == uiBodys[i].getAttributeValue(ICPubMetaNameConst.CMATERIALVID)) {
					continue;
				}
				if (!NCBaseTypeUtils.isNullOrZero((UFDouble) uiBodys[i].getAttributeValue(ICPubMetaNameConst.NNUM))) {
					continue;
				}
				uiBodys[i].setAttributeValue(ICPubMetaNameConst.VNOTEBODY, errMsg);
//				uiBodys[i].setAttributeValue(ICPubMetaNameConst.CROWNO, i);
			}
			return;
		}

		for (int i = 0, loop = uiBodys.length; i < loop; i++) {
			ICBillBodyVO[] bodys = results.getPickBodys(i);
			if (!ValueCheckUtil.isNullORZeroLength(bodys)) {
				continue;
			}

			if (null == uiBodys[i].getAttributeValue(ICPubMetaNameConst.CMATERIALVID)) {
				continue;
			}
			if (!NCBaseTypeUtils.isNullOrZero((UFDouble) uiBodys[i].getAttributeValue(ICPubMetaNameConst.NNUM))) {
				continue;
			}
			uiBodys[i].setAttributeValue(ICPubMetaNameConst.VNOTEBODY, errMsg);
		}

	}

	private void loadInvCalBodyInfo(ICBillVO billvo) {
		String pk_org = (String) billvo.getHead().getAttributeValue(ICPubMetaNameConst.PK_ORG);
		ICBillBodyVO[] uiBodys = billvo.getBodys();
		Set<String> invpks = new HashSet<String>();
		for (int i = 0; i < uiBodys.length; i++) {
			String cmaterialvid = (String) uiBodys[i].getAttributeValue(ICPubMetaNameConst.CMATERIALVID);
			if (StringUtil.isSEmptyOrNull(cmaterialvid)) {
				continue;
			}
			invpks.add(cmaterialvid);
		}

		if (invpks.size() == 0) {
			return;
		}
		InvBasAndCalInfo[] invInfos = new ICBSContext().getInvInfo().getInvBasAndCalInfo(pk_org,
				invpks.toArray(new String[0]));
		if (invInfos == null || invInfos.length == 0) {
			return;
		}
		// this.invcalbodysmap =
		// CollectionUtils.hashVOArray(MaterialStockVO.PK_MATERIAL, invInfos);
		this.invInfoMap = this.setInvBasInfosToMap(invInfos);
	}

	private Map<String, InvBasAndCalInfo> setInvBasInfosToMap(InvBasAndCalInfo[] invInfos) {
		Map<String, InvBasAndCalInfo> infoMap = new HashMap<String, InvBasAndCalInfo>();
		for (InvBasAndCalInfo info : invInfos) {
			// BUG:如果没有分配到库存组织，就跳过，否则会报错
			if (info == null || info.getInvcalbodyvo() == null) {
				continue;
			}
			String key = info.getInvcalbodyvo().getPk_material();
			infoMap.put(key, info);
		}
		return infoMap;
	}

	/**
	 * 得到界面的物料是否辅计量记结存
	 *
	 * @return
	 */
	private void getBAstunitStorebalance(ICBillVO billvo) {
		ICBillBodyVO[] bodyvos = billvo.getBodys();
		this.isasunitstore = null;
		Set<String> invmeasPkSet = new HashSet<String>();
		List<String> invpks = new ArrayList<String>();
		List<String> measpks = new ArrayList<String>();
		for (int i = 0; i < bodyvos.length; i++) {
			String invpk = (String) bodyvos[i].getAttributeValue(ICPubMetaNameConst.CMATERIALVID);
			if (StringUtil.isSEmptyOrNull(invpk)) {
				continue;
			}
			String measpk = (String) bodyvos[i].getAttributeValue(ICPubMetaNameConst.CASTUNITID);
			;
			if (StringUtil.isSEmptyOrNull(measpk)) {
				continue;
			}
			String key = invpk + measpk;
			if (!invmeasPkSet.contains(key)) {
				invmeasPkSet.add(key);
				invpks.add(invpk);
				measpks.add(measpk);
			}

		}
		InvMeasVO[] invmeasvos = new ICBSContext().getInvInfo().getInvMeasVO(invpks.toArray(new String[invpks.size()]),
				measpks.toArray(new String[measpks.size()]));
		Map<String, UFBoolean> bastunitstore = new HashMap<String, UFBoolean>();
		if (invmeasvos != null) {
			for (InvMeasVO invMeasVO : invmeasvos) {
				if (invMeasVO == null) {
					// 物料可能没有辅计量信息
					continue;
				}
				bastunitstore.put(invMeasVO.getPk_material() + invMeasVO.getPk_measdoc(),
						invMeasVO.getIsstorebalance());
			}
		}

		this.isasunitstore = bastunitstore;
	}

	/**
	 * 同步序列号档案上信息到孙表
	 * 
	 * @param billvo
	 * @param results
	 *
	 */
	private void fillSNDocToLocation(ICBillVO billvo, ICBillPickResults results) {
		List<ICLocationVO> locs = new ArrayList<ICLocationVO>();
		for (int i = 0, loop = billvo.getBodys().length; i < loop; i++) {
			ICBillBodyVO[] bodys = results.getPickBodys(i);
			if (ValueCheckUtil.isNullORZeroLength(bodys)) {
				continue;
			}
			for (ICBillBodyVO body : bodys) {
				if (body == null) {
					continue;
				}
				CollectionUtils.addArrayToList(locs, body.getLocationVOs());
			}
		}
		// 同步序列号相关信息到孙表，ICSnForLocationFields继承了AbstractBatchFieldMap，父类的作用是同步批次信息
		new SnCodeForLocationVOSynchronizer(new ICSnForLocationFields())
				.fillBatchVOtoBill(locs.toArray(new ICLocationVO[0]));
	}

}
