package com.dev.swms.server.service.picking.allocate;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.comparators.ComparatorChain;
import org.apache.commons.collections.comparators.ReverseComparator;

import com.dev.swms.server.model.abstractEntity.AbstractMoveDoc;
import com.dev.swms.server.model.abstractEntity.AbstractMoveDocDetail;
import com.dev.swms.server.model.base.BillType;
import com.dev.swms.server.model.base.CompanyCode;
import com.dev.swms.server.model.base.Item;
import com.dev.swms.server.model.base.ItemKey;
import com.dev.swms.server.model.base.Location;
import com.dev.swms.server.model.base.LocationType;
import com.dev.swms.server.model.base.LotInfo;
import com.dev.swms.server.model.base.NewLotInfo;
import com.dev.swms.server.model.base.Structure;
import com.dev.swms.server.model.base.PackageUnit;
import com.dev.swms.server.model.base.TurnOverMode;
import com.dev.swms.server.model.base.Warehouse;
import com.dev.swms.server.model.inventory.Inventory;
import com.dev.swms.server.model.inventory.ItemKeyInventory;
import com.dev.swms.server.model.inventory.ProcessDoc;
import com.dev.swms.server.model.inventory.ProcessDocBOMDetail;
import com.dev.swms.server.model.inventory.Stock;
import com.dev.swms.server.model.inventory.Task;
import com.dev.swms.server.model.inventory.TaskType;
import com.dev.swms.server.model.receiving.MoveDoc;
import com.dev.swms.server.model.receiving.MoveDocDetail;
import com.dev.swms.server.model.receiving.MoveDocStatus;
import com.dev.swms.server.model.rules.ItemStorageRule;
import com.dev.swms.server.model.rules.PickItemRule;
import com.dev.swms.server.model.rules.PickMethod;
import com.dev.swms.server.model.rules.SortRule;
import com.dev.swms.server.model.shipping.LotQuantity;
import com.dev.swms.server.model.shipping.PickTicket;
import com.dev.swms.server.model.shipping.PickTicketDetail;
import com.dev.swms.server.model.shipping.PickTicketStatus;
import com.dev.swms.server.model.shipping.PreAllocate;
import com.dev.swms.server.model.shipping.WaveDoc;
import com.dev.swms.server.model.shipping.WaveDocDetail;
import com.dev.swms.server.model.shipping.WaveDocStatus;
import com.dev.swms.server.service.base.ItemManager;
import com.dev.swms.server.service.inventory.InventoryManager;
import com.dev.swms.server.service.receiving.PutawayAllocator;
import com.dev.swms.server.service.sequence.BussinessCodeManager;
import com.dev.swms.server.utils.DateUtil;
import com.dev.swms.server.utils.DateUtils;
import com.dev.swms.server.utils.DoubleUtils;
import com.dev.swms.server.utils.NewLotInfoParser;
import com.dev.swms.server.web.filter.WarehouseHolder;
import com.dev.energy.client.utils.StringUtils;
import com.dev.energy.server.exception.BusinessException;
import com.dev.energy.server.model.EntityFactory;
import com.dev.energy.server.service.pojo.DefaultBaseManager;
import com.dev.energy.server.util.LocalizedMessage;

/**
 * @author  dev
 *
 */
public class DefaultAutoAllocator extends DefaultBaseManager implements AutoAllocator {
	protected final ItemManager itemManager;
	protected final InventoryManager inventoryManager;
	protected final BussinessCodeManager bussinessCodeManager;
	protected final PutawayAllocator putawayAllocator;
	private Long warehouseId;
	
	
    public DefaultAutoAllocator(ItemManager manager,InventoryManager manager1,
    		BussinessCodeManager manager2, PutawayAllocator allocator) {
		itemManager = manager;
		inventoryManager = manager1;
		bussinessCodeManager = manager2;
		putawayAllocator = allocator;
	}

	/**
	 * 拣货分配过程
	 * @param moveDocDetails
	 */
	@SuppressWarnings("unchecked")
	private String allocateInventoryForPickItemRule(Collection<AbstractMoveDocDetail> moveDocDetails) {
		String errmsg = "";
		Structure company = null;
		BillType billType = null;
		Warehouse warehouse = null;
		List<AbstractMoveDocDetail> replDetails = new ArrayList<AbstractMoveDocDetail>();
		boolean isPickingAllocate = Boolean.FALSE;
        for(AbstractMoveDocDetail moveDocDetail : moveDocDetails){
        	if (!isPickingAllocate && (moveDocDetail instanceof PickTicketDetail 
        			|| moveDocDetail instanceof WaveDocDetail)) {
        		isPickingAllocate = Boolean.TRUE;
        	}
        	String loc_code=null;
        	String loc="'STORAGE','TRANSIT'";
        	if(moveDocDetail instanceof PickTicketDetail){//当货品补货位不为空，且零散数量只能从拣货位出
        	if (moveDocDetail.getItem().getCompany() != null) {
            	company = moveDocDetail.getItem().getCompany();
        	}
        	Boolean bh=Boolean.FALSE;
        	if(moveDocDetail.getItem().getLocation()!=null){
        		 bh=Boolean.TRUE;
        }
        	if (billType == null) {
        		billType = moveDocDetail.getAbstractMoveDoc().getBillType();
        	}
        	if (warehouse == null) {
    			warehouse = moveDocDetail.getAbstractMoveDoc().getWarehouse();
        	}
        	ItemStorageRule isr = moveDocDetail.getItem().getWarehouseItemStorageRule();
        	
        	Location dstLoc = moveDocDetail.getAllocateDstLoc();
        	//如果发货单明细无未分配数量，则忽略
        	if (moveDocDetail.getUnallocateQuantity() <= 0) {
        		continue;
        	}
        	
        	String itemPickType = null;
        	if(isr != null && isr.getItemPickType() != null){
        		itemPickType = isr.getItemPickType();
        	}
        	String abcType = null;
        	if(isr != null && isr.getAbcType() != null) {
        		abcType = isr.getAbcType().getAbcType();
        	}

    		List<InventoryWrap> tempInventories = new ArrayList<InventoryWrap>();
    		PickItemRule pickItemRule=null;
        	double totalQty = 0.0;
    	    	Item item = moveDocDetail.getItem();
    			NewLotInfo lotInfo = moveDocDetail.getNewLotInfo() == null ? new NewLotInfo() : moveDocDetail.getNewLotInfo();
    			//按库位或库位分类过滤库存
    			String locHql = "";
    			//不包含目标库位库存
    			if (dstLoc != null) {
    				locHql += " AND inventory.location.id <> " + dstLoc.getId();
    			}
    			//按包装分配库存
    			//按SOI分配库存
    			if (!StringUtils.isEmpty(moveDocDetail.getSOI())) {
    				locHql += " AND inventory.SOI = '" + moveDocDetail.getSOI() + "'";
    			}
    			
    			StringBuffer sb = new StringBuffer();
    	    	    String hql =sb.append("SELECT new com.dev.swms.server.service.picking.allocate.InventoryWrap(inventory) FROM Inventory inventory ")
    			.append("WHERE inventory.warehouse.id=:warehouseId ")
    			.append("AND inventory.itemKey.item.id = :itemId")
				.append(" AND (inventory.beLock=0 )")
    			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
    			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
    			.append(" AND (inventory.qtyOfMasterPack - inventory.queuedQuantity) > 0")
    			.append(" AND inventory.location.type in ("+loc+")")
    			.append(locHql)
    			.toString();
    	    	   
//    		    	if(lotInfo.getPropD2()!=null){
//    		    		hql+=" and DATE_FORMAT(inventory.itemKey.lotInfo.propD2,'%Y-%m-%d')='"+lotInfo.getPropD2()+"'";
//    		    	}
//    	    	    
//    	    	    if(lotInfo.getPropD1()!=null&&!lotInfo.getPropD1().equals("")){
//    		    		hql+=" and DATE_FORMAT(inventory.itemKey.lotInfo.propD1,'%Y-%m-%d')='"+lotInfo.getPropD1()+"'";
//    		    	}
		    	if(loc_code!=null&&!loc_code.equals("")){
		    		hql+=" and inventory.location.code ='"+loc_code+"'";
		    	}
		     	if(moveDocDetail instanceof WaveDocDetail){
		     		hql+=" and inventory.location.code !='"+moveDocDetail.getItem().getLocation().getCode()+"'";
		     	}
    	    	tempInventories.addAll(this.commonDao.findByQuery(hql, 
    	    			new String[] {"warehouseId", "itemId"}, 
    	    			new Object[] {warehouse.getId(), item.getId()}));
            	String turnOverMode = null; //库存周转方式
            	if(moveDocDetail instanceof WaveDocDetail){
             		if(((WaveDocDetail)moveDocDetail).getWaveDoc().getTurnOverMode()!= null){
             			turnOverMode = ((WaveDocDetail)moveDocDetail).getWaveDoc().getTurnOverMode();
             		}
            	}else if(moveDocDetail instanceof PickTicketDetail){
             		Structure customer = ((PickTicketDetail)moveDocDetail).getPickTicket().getCustomer();
             		if(customer!=null&&customer.getCustomerTurnOverMode()!= null){
             			turnOverMode = customer.getCustomerTurnOverMode();
             		}
             	}
            	if(turnOverMode==null && company.getCompanyTurnOverMode() != null){
            		turnOverMode = company.getCompanyTurnOverMode();
             	}
                if (tempInventories.size()>0) {
	                	List<Inventory> inventories=new ArrayList<Inventory>();
	                	for(InventoryWrap inv:tempInventories){
	                		inventories.add(inv.getInventory());
	                	}
	                	//拣货分配，累加已分配数量
	                 totalQty += allocateInventory(null,inventories, moveDocDetail);
                }
               
//                if((moveDocDetail.getPreAllocatedQuantity()-moveDocDetail.getAllocatedQuantity())<=0){
//                		continue;
//                		//break;
//                }else{
//                	 System.out.println(moveDocDetail.getItem()+"===="+moveDocDetail.getAllocatedQuantity());
//                }
        	}
        	
        	if (moveDocDetail.getUnallocateQuantity() > 0 
        			&& moveDocDetail.getItem().getPackageUnitByLineNo(2) != null
        			&& moveDocDetail.getPackageUnit().getLineNO() == 1
        			&& company.isBatchPickingSupply()) {
        		//货主允许批量拣货补货，分配数量不足，货品有大包装，且发货单明细中的包装为基本包装时，自动产生补货计划
        		replDetails.add(moveDocDetail);
        	}
        }
        
//        if (isPickingAllocate && replDetails.size() > 0) {
//        	createSupplyDoc(warehouse, company, replDetails);
//        }
        
        return errmsg;
	}
	
	/**
	 * 拣货分配过程
	 * @param moveDocDetails
	 */
	@SuppressWarnings("unchecked")
	private String allocateInventoryForPickItemRule_New(String code,Collection<AbstractMoveDocDetail> moveDocDetails) {
		String errmsg = "";
		Warehouse warehouse = null;
        for(AbstractMoveDocDetail moveDocDetail : moveDocDetails){
        	//如果发货单明细无未分配数量，则忽略
        	System.out.println(moveDocDetail.getItem().getId()+"==="+moveDocDetail.getItem().getCode()+"==="+moveDocDetail.getUnallocateQuantity());
        	if (moveDocDetail.getUnallocateQuantity() <= 0) {
        		continue;
        	}
        	String loc_code=null;
        	String loc_type="'STORAGE','TRANSIT'";
        	warehouse = moveDocDetail.getAbstractMoveDoc().getWarehouse();
//        	if(moveDocDetail instanceof PickTicketDetail){//当货品补货位不为空，且零散数量只能从拣货位出
//        		PickTicketDetail d=(PickTicketDetail)moveDocDetail;
//        		warehouse = moveDocDetail.getAbstractMoveDoc().getWarehouse();
//        		loc_type="'STORAGE','TRANSIT'";
//        	}
//        	Boolean bh=Boolean.FALSE;
//        	if(moveDocDetail.getItem().getLocation()!=null){
//        		 bh=Boolean.TRUE;
//        	}
//        	Location dstLoc = moveDocDetail.getAllocateDstLoc();
    		List<Inventory> tempInventories = new ArrayList<Inventory>();
        	double totalQty = 0.0;
	    	Item item = moveDocDetail.getItem();
			NewLotInfo lotInfo = moveDocDetail.getNewLotInfo() == null ? new NewLotInfo() : moveDocDetail.getNewLotInfo();
			String locHql = "";
			//不包含目标库位库存
//			if (dstLoc != null) {
//				locHql += " AND inventory.location.id <> " + dstLoc.getId();
//			}
    			StringBuffer sb = new StringBuffer();
    	    	String hql =sb.append(" FROM Inventory inventory ")
    			.append("WHERE inventory.location.warehouse.id=:warehouseId ")
    			.append("AND inventory.itemKey.item.id = :itemId")
//				.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC3",lotInfo.getPropC3()))
    			.append(" AND (inventory.status is null or inventory.status = '' or inventory.status = '非破损')")
    			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
    			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
    			.append(" AND (inventory.qtyOfMasterPack - inventory.queuedQuantity) > 0")
    			.append(" AND inventory.location.type in ("+loc_type+")")
    			.append(locHql)
    			.toString();
//    	    	    if(lotInfo.getPropD1()!=null){
//    		    		hql+=" and to_char(inventory.itemKeyInventory.itemKey.lotInfo.propD1,'yyyy-mm-dd')='"+lotInfo.getPropD1()+"'";
//    		    	}
//    		    	if(loc_code!=null){
//    		    		hql+=" and inventory.location.code ='"+loc_code+"'";
//    		    	}
//			     	if(moveDocDetail instanceof WaveDocDetail){
//			     		hql+=" and inventory.location.code !='"+moveDocDetail.getItem().getLocation().getCode()+"'";
//			     	}
    		    	hql+=" order by inventory.location.type desc ";
    		    	hql+=" ,inventory.itemKey.lotInfo.propD2 asc";
    		    	hql+=", (inventory.qtyOfMasterPack - inventory.queuedQuantity) asc";
    		    	hql+=" ,inventory.location.code asc";
    		    	hql+=" ,inventory.location.sortIndex asc";
    		    	System.out.println(item.getId()+"a1==="+new Date());
    	    	tempInventories.addAll(this.commonDao.findByQuery(hql, 
    	    			new String[] {"warehouseId", "itemId"}, 
    	    			new Object[] {warehouse.getId(), item.getId()}));
    	    	System.out.println("a2==="+new Date());
                if (tempInventories.size()>0) {
	                 totalQty += allocateInventory(code,tempInventories, moveDocDetail);
	                 System.out.println("a3==="+new Date());
                if((moveDocDetail.getPreAllocatedQuantity()-moveDocDetail.getAllocatedQuantity())<=0){
                		//break;
                	continue;
                }else{
                	 System.out.println(moveDocDetail.getItem()+"===="+moveDocDetail.getAllocatedQuantity());
                }
        	}
        	
        }
        
        return errmsg;
	}
	
	/**
	 * getPickItemRuleForPickTicket需要传入的参数中,pickQuantityMinPU是最小单位数量,pickQuantity为当前包装单位数量
	 * 筛选捡货规则的时候,如果规则和包装单位有关,则规则的最小最大捡货数量是对应规则相关包装单位的数量;
	 * 如果规则和包装单位无关,则规则的最小最大捡货数量对应最小包装数量
	 */
	@SuppressWarnings("unchecked")
	public List<PickItemRule> getPickItemRules(Structure company,BillType billType,String itemPickType,
			Item item,PackageUnit packageUnit,LotInfo lotInfo,double quantity,String abcType){
		Long billTypeId = null;
		if(billType!=null)
			billTypeId = billType.getId();
		
		List<PickItemRule> pickItemRules  = this.commonDao.findByNamedQuery("getPickItemRuleForPickTicket",
				new String[]{"warehouseId","companyId","billTypeId","itemPickType","itemId","packageLineNo",
				"itemBigType","itemMiddleType","itemLittleType","pickQuantityMinPU","pickQuantity","abcType"},
				new Object[]{WarehouseHolder.getWarehouse().getId(),company.getId(),
				billTypeId,
				itemPickType,
				item.getId(),
				packageUnit.getLineNO(),
				item.getLargeClass(),
				item.getCenterClass(),
				item.getSmallClass(),
				quantity,
				DoubleUtils.formatByPrecision(quantity/packageUnit.getConvertFigure(), packageUnit.getPrecision()), 
				abcType});
		
		return pickItemRules;
	}
	
	/**
     * @param inventories
     * @param relateProperties
     * @return
     */
	@SuppressWarnings("unchecked")
    private  Map<String, List<Inventory>> sortByRule(List<InventoryWrap> inventoryWraps, ItemStorageRule storageRule, PickItemRule pickItemRule1,String turnOverMode) {
        //收集排序规则
        List<SortRule> sortRules = new ArrayList<SortRule>();
      //如果货主允许拆托分配，则分配托盘库存时托盘库存数量从小到大分配（托盘被过多的拆托）；如果不允许拆托，则数量从大到小排列（避免错误的分配不足）
//        if(pickItemRule.getCompany().isBeAllowedSplitLPForAllocate()){
//        	sortRules.add(new SortRule(1, "avaliableQuantity", "DESC"));
//        }else{
        	sortRules.add(new SortRule(1, "avaliableQuantity", "ASC"));
//        }
      		sortRules.add(new SortRule(2, "locationType", "desc"));
//      	sortRules.add(new SortRule(1, "quantity", "DESC"));
        //先按照库存周转排序
        if(turnOverMode != null){
        	if (TurnOverMode.FIFO_STORAGEDATE.equals(turnOverMode)) {
        		sortRules.add(new SortRule(3, "storageDate", "ASC"));
        	} else if (TurnOverMode.LIFO_STORAGEDATE.equals(turnOverMode)) {
        		sortRules.add(new SortRule(3, "storageDate", "DESC"));
        	} else if (TurnOverMode.FIFO_VALIDDATE.equals(turnOverMode)) {
        		sortRules.add(new SortRule(3, "expireDate", "ASC"));
        	} else if (TurnOverMode.LIFO_VALIDDATE.equals(turnOverMode)) {
        		sortRules.add(new SortRule(3, "expireDate", "DESC"));
        	} 
        }
      
        //按照库位状态排序，拣、空、存
//        if(PickMethod.PICK_STORE.equals(pickItemRule.getPickMethod())){
        		sortRules.add(new SortRule(4, "locationStatus", "DESC"));
//        }else{
//        		sortRules.add(new SortRule(4, "locationStatus", "ASC"));
//        }
        //4
       	//参考库位编号顺序排列,保证一个库位的库存在一起
       	sortRules.add(new SortRule(5, "locationCode", "ASC"));
       	//将托盘库存和非托盘库存分开排序，由于lpIndex为字符串，排序结果是：'','1','2','3',...[非托盘在前，托盘在后，托盘按照排序号依次排列]
       	sortRules.add(new SortRule(6, "lpIndex", "ASC"));
        //将大包装放前面
        sortRules.add(new SortRule(7, "convertFigure", "DESC"));
        //构造排序Chain
        ComparatorChain chain =  new ComparatorChain();
        for (SortRule sortRule : sortRules) {
            if (sortRule.getSortMethod().equals("DESC")) { 
                chain.addComparator(new ReverseComparator(new BeanComparator(sortRule.getSortKey())));
            } else {
                chain.addComparator(new BeanComparator(sortRule.getSortKey()));
            }
        }
        
        //排序处理
        Collections.sort(inventoryWraps,chain);
        
        /**
         *  a、库位上有整托和非整托时，如果待拣数量大于整托，则先分配整托； 
         *	b、库位上有非整托时，如果待拣数量不够整托，先分配非整托； 
         *	c、库位上托盘分配后，如果分配数量仍不足，则查找非托盘散货（inventory中lp为''的库存记录），按包装大小顺序分配；
         */
        //将托盘库存排到非托盘库存前
        List<Inventory> tempInvs1 = new ArrayList<Inventory>();
        List<Inventory> tempInvs2 = new ArrayList<Inventory>();
        
        List<Inventory> tempInvsBH1 = new ArrayList<Inventory>();
        List<Inventory> tempInvsBH2 = new ArrayList<Inventory>();
        for(InventoryWrap inventoryWrap : inventoryWraps){
        	if(inventoryWrap.getInventory().getLP() == null){
//        		if(bh&&inventoryWrap.getInventory().getLocation().getType().equals(LocationType.TRANSIT)){
//        			tempInvsBH2.add(inventoryWrap.getInventory());
//        		}else{
        			tempInvs2.add(inventoryWrap.getInventory());
//        		}
        	}else{
//        		if(bh&&inventoryWrap.getInventory().getLocation().getType().equals(LocationType.TRANSIT)){
//        			tempInvsBH1.add(inventoryWrap.getInventory());
//        		}else{
        			tempInvs1.add(inventoryWrap.getInventory());
//        		}
        	}
        }
        tempInvs1.addAll(tempInvs2);
        
        
        
        tempInvsBH1.addAll(tempInvsBH2);
        Map<String,List<Inventory>> maps=new HashMap<String,List<Inventory>>();
        maps.put("CA", tempInvs1);
        maps.put("BH", tempInvsBH1);
        return maps;
    }
 
	public void preAllocate(Collection<PickTicketDetail> pickTicketDetails) {
        for(PickTicketDetail pickTicketDetail : pickTicketDetails){
		    	if (pickTicketDetail.getUnPreAllocateQuantity() > 0) {
		    		preAllocate(pickTicketDetail, pickTicketDetail.getUnPreAllocateQuantity(),"3");
		    		
		    	}
        }
	}
	
	public void prePlanAllocate(Collection<PickTicketDetail> pickTicketDetails) {
        for(PickTicketDetail d : pickTicketDetails){
	        	if (d.getUnPreAllocateQuantity() > 0) {
	        		preAllocate(d, d.getUnPreAllocateQuantity());
	        	}
        }
	}

	@SuppressWarnings("unchecked")
	public void preAllocate(PickTicketDetail pickTicketDetail, Double quantity,String type) {
    	Warehouse warehouse = pickTicketDetail.getAbstractMoveDoc().getWarehouse();
    	Item item = pickTicketDetail.getItem();
    	NewLotInfo lotInfo = pickTicketDetail.getNewLotInfo() == null ? new NewLotInfo() : pickTicketDetail.getNewLotInfo();
    	itemManager.formatNewLotInfo(lotInfo);
    	String lot = "";
    	String code = pickTicketDetail.getCode();
    	String loc="";
	if(type.equals("1")){
		loc="'TRANSIT'";
	}else if(type.equals("2")){
		loc="'STORAGE','TRANSIT'";
	}else if(type.equals("3")){
		loc="'STORAGE','TRANSIT','READY'";
	}
    	//批次属性匹配(是否按照批次属性严格匹配)
    	StringBuffer sb = new StringBuffer();
    	String hql =sb.append("SELECT new com.dev.swms.server.model.shipping.LotQuantity(inventory.itemKeyInventory.itemKey.lot,")
			.append("SUM(inventory.qtyOfMasterPack)) ")
			.append("FROM Inventory inventory ")
			.append("WHERE inventory.itemKeyInventory.warehouse.id = :warehouseId ")
			.append(" AND inventory.itemKeyInventory.itemKey.item.id = :itemId")
			.append(" AND (" )
			.append(NewLotInfoParser.decryptStringOfLot("propC1",lotInfo.getPropC1()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC2",lotInfo.getPropC2()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC3",lotInfo.getPropC3()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC4",lotInfo.getPropC4()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC5",lotInfo.getPropC5()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC6",lotInfo.getPropC6()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC7",lotInfo.getPropC7()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC8",lotInfo.getPropC8()))
//			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC9",lotInfo.getPropC9()))
//			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN1",lotInfo.getPropN1()))
//			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN2",lotInfo.getPropN2()))
//			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN3",lotInfo.getPropN3()))
			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD1",lotInfo.getPropD1()))
			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD2",lotInfo.getPropD2()))
//			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD3",lotInfo.getPropD3()))
//			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC1",lotInfo.getPropL1()))
//			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC2",lotInfo.getPropL2()))
//			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC3",lotInfo.getPropL3()))
			.append(" ) ")
			.append(" AND (inventory.status is null or inventory.status = '')")
			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
			.append(" AND inventory.location.type IN ("+loc+") ")
		    .append(" GROUP BY inventory.itemKeyInventory.itemKey.lot")
			.append(" ORDER BY SUM(inventory.qtyOfMasterPack) DESC").toString();    		
    		
    		List<LotQuantity> results = this.commonDao.findByQuery(hql, 
            		new String[] {"warehouseId", "itemId"},
            		new Object[] {warehouse.getId(), item.getId()});
    	
        Double inventoryQty = 0D;
        if (results != null && results.size() > 0) {
        	//提取批次号并计算可预分配库存总数量
        	for (int i=0;i<results.size();i++) {
            	if (StringUtils.isEmpty(lot)) {
                	lot = String.valueOf(results.get(i).getLot());
            	}
        		inventoryQty += results.get(i).getQuantity();
        	}
        }
        if (inventoryQty <= 0) {
        	return;
        }
        Double preAllocatedQty = (Double) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateQtyByCondition", 
        		new String[] {"warehouseId", "itemId", "lot"},
        		new Object[] {warehouse.getId(), item.getId(), lot});
        if (preAllocatedQty == null) {
        		preAllocatedQty = 0D;
        }
		//库存数量不足，按可用库存分配
        if ((preAllocatedQty + quantity) > inventoryQty) {
        	quantity = (inventoryQty - preAllocatedQty);
    		//如果可预分配数量小于0，返回错误信息
    		if (quantity <= 0) {
    			return;
    		}
    	}
    	//检查预分配数量
    	
    	//检查是否有重复的预分配记录
    	PreAllocate preAllocate = (PreAllocate) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateByUK", new String[] {"code", "warehouseId", "itemId", "lot"}, new Object[] {code, warehouse.getId(), item.getId(), lot});
    	if (preAllocate == null) {
        	preAllocate = EntityFactory.getEntity(PreAllocate.class);
        	preAllocate.setCode(code);
        	preAllocate.setWarehouse(warehouse);
        	preAllocate.setItem(pickTicketDetail.getItem());
        	preAllocate.setLot(lot);
    	}
    	preAllocate.preAllocate(quantity);
    	this.commonDao.store(preAllocate);
    	
    	pickTicketDetail.preAllocate(lot, quantity);
	}
	
	@SuppressWarnings("unchecked")
	public void preAllocate(PickTicketDetail d, Double quantity) {
    	Warehouse warehouse = d.getPickTicket().getWarehouse();
    	Item item = d.getItem();
    	NewLotInfo lotInfo = d.getNewLotInfo() == null ? new NewLotInfo() : d.getNewLotInfo();
    	itemManager.formatNewLotInfo(lotInfo);
    	String loc="";
	loc="'STORAGE','TRANSIT','READY'";
	Date d1=null;
	Date d2=null;
	if(lotInfo.getPropD1()!=null){
		d1=DateUtil.formatDate(lotInfo.getPropD1());
	}
	if(lotInfo.getPropD2()!=null){
		d2=DateUtil.formatDate(lotInfo.getPropD2());
	}
    	//批次属性匹配(是否按照批次属性严格匹配)
    	StringBuffer sb = new StringBuffer();
    	String hql =sb.append("SELECT ")
			.append("COALESCE(SUM(inventory.qtyOfMasterPack),0) ")
			.append("FROM Inventory inventory ")
			.append("WHERE inventory.itemKeyInventory.warehouse.id = :warehouseId ")
			.append(" AND inventory.itemKeyInventory.itemKey.item.id = :itemId")
//			.append(" AND (inventory.status is null or inventory.status = '' or inventory.status = '非破损')")
			.append(" AND (inventory.beLock=0 )")
			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
			.append(" AND inventory.location.type IN ("+loc+") ").toString(); 
	    	if(lotInfo!=null){
		    	if(lotInfo.getPropD1()!=null){
		    		hql+=" and DATE_FORMAT(inventory.itemKeyInventory.itemKey.lotInfo.propD1,'%Y-%m-%d')='"+lotInfo.getPropD1()+"'";
		    	}
		    	if(lotInfo.getPropD2()!=null){
		    		hql+=" and DATE_FORMAT(inventory.itemKeyInventory.itemKey.lotInfo.propD2,'%Y-%m-%d')='"+lotInfo.getPropD2()+"'";
		    	}
	    	}
        Double inventoryQty = (Double)this.commonDao.findByQuery(hql, 
        		new String[] {"warehouseId", "itemId"},
        		new Object[] {warehouse.getId(), item.getId()}).get(0);
        if (inventoryQty <= 0) {
        		return;
        }
        //查找该批次已经预分配的库存
        String preHql="select COALESCE(sum(preAllocatedQuantity-allocatedQuantity),0) from PickTicketDetail d where d.item.id="+item.getId()+" and d.pickTicket.warehouse.id="+warehouse.getId();
        if(lotInfo==null){
        		preHql+=" and d.newLotInfo is null";
        }else{
	        	if(lotInfo.getPropD1()!=null){
	        		preHql+=" and d.newLotInfo.propD1='"+lotInfo.getPropD1()+"'";
		    	}
        		if(lotInfo.getPropD2()!=null){
        			preHql+=" and d.newLotInfo.propD2='"+lotInfo.getPropD2()+"'";
		    	}
        }
        preHql+=" and d.pickTicket.allocatedQuantity<=0 ";
        Double preAllocatedQty = (Double)commonDao.findByQuery(preHql).get(0);
		//库存数量不足，按可用库存分配
        if ((preAllocatedQty + quantity) > inventoryQty) {
        		quantity = (inventoryQty - preAllocatedQty);
	    		//如果可预分配数量小于0，返回错误信息
	    		if (quantity <= 0) {
	    			return;
	    		}
        }
    	d.preAllocate(null,quantity);
    	this.commonDao.store(d);
	}
	public void unPreAllocate(Collection<PickTicketDetail> pickTicketDetails) {
        for(PickTicketDetail pickTicketDetail : pickTicketDetails){
        	unPreAllocate(pickTicketDetail, pickTicketDetail.getUnallocateQuantity());
        }
	}

	public void unPreAllocate(PickTicketDetail pickTicketDetail, Double quantity) {
    	Warehouse warehouse = pickTicketDetail.getAbstractMoveDoc().getWarehouse();
    	Item item = pickTicketDetail.getItem();
    	String lot = pickTicketDetail.getPreAllocatedLot();
    	String code = pickTicketDetail.getCode();
    	Double unPreAllocateQty = (pickTicketDetail.getPreAllocatedQuantity() - pickTicketDetail.getAllocatedQuantity());
    	if (quantity == 0) {
    		return;
    	}
    	if (quantity > unPreAllocateQty) {
    		throw new BusinessException("unPreAlloate.quantity.error");
    	}	
		//发货单明细取消预分配
		pickTicketDetail.unPreAllocate(quantity);
		//修改预分配表
    	PreAllocate preAllocate = (PreAllocate) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateByUK", new String[] {"code", "warehouseId", "itemId", "lot"}, new Object[] {code, warehouse.getId(), item.getId(), lot});
		if (preAllocate == null) {
			throw new BusinessException("preAllocate.match.none");
		} else {
			//如果取消预分配后记录的预分配数量为0，则删除该预分配记录
			preAllocate.unPreAllocate(quantity);
			if (preAllocate.getPreAllocatedQuantity() == 0) {
				this.commonDao.delete(preAllocate);
			}
		}
	}
	
	public void unallocate(AbstractMoveDoc moveDoc) {
		warehouseId = WarehouseHolder.getWarehouse().getId().longValue();
		synchronized (warehouseId) {
			for(AbstractMoveDocDetail detail : moveDoc.getAbstractMoveDocDetails()){
				String barCode=null;
				List<Task> ts = new ArrayList<Task>();
				for (Task task: detail.getTasks()) {
					if(TaskType.MV_CROSS.equals(task.getType())){
						continue;
					}
					double quantity = task.getPlanQuantityMU() - task.getMovedQuantityMU();
					if (quantity == 0) {
						ts.add(task);
						continue;
					}
					

					if (moveDoc instanceof PickTicket) {
						task.unallocatePick(quantity);
					} else if(moveDoc instanceof WaveDoc){
						task.unallocateWaveDoc(quantity);
					}else if(moveDoc instanceof ProcessDoc){
						task.unallocateProcessDoc(quantity);
					}else{
						task.unallocateMove(quantity);
					}

					ItemKeyInventory itemKeyInventory = inventoryManager.getItemKeyInventory(
							task.getSrcLoc().getWarehouse(), task.getItemKey());
					Inventory inventory = itemKeyInventory.getInventoryWithException(task.getSrcLoc(), 
							task.getPackageUnit(), task.getSrcLP(),barCode, task.getInventoryStatus(), 
							task.getStorageDate(), task.getSOI());
					inventory.unallocate(quantity, null, null);

					if (task.getPlanQuantityMU()== 0) {
						ts.add(task);
					}
				}
				detail.getTasks().removeAll(ts);
			}
		}
	}
	
	public void unallocate(AbstractMoveDoc moveDoc,List<PickTicketDetail> details) {
		warehouseId = WarehouseHolder.getWarehouse().getId().longValue();
		synchronized (warehouseId) {
			for(AbstractMoveDocDetail detail : details){
				List<Task> ts = new ArrayList<Task>();
				for (Task task: detail.getTasks()) {
					if(TaskType.MV_CROSS.equals(task.getType())){
						continue;
					}
					double quantity = task.getPlanQuantityMU() - task.getMovedQuantityMU();
					if (quantity == 0) {
						ts.add(task);
						continue;
					}
					

					if (moveDoc instanceof PickTicket) {
						task.unallocatePick(quantity);
					} else if(moveDoc instanceof WaveDoc){
						task.unallocateWaveDoc(quantity);
					}else if(moveDoc instanceof ProcessDoc){
						task.unallocateProcessDoc(quantity);
					}else{
						task.unallocateMove(quantity);
					}
					ItemKey itemKey=task.getItemKey();
					Inventory inventory=null;
					if(itemKey.getInventories().size()>0) {
						
						for(Inventory inv:itemKey.getInventories()) {
							inventory=inv;
							break;
						}
						
					}
//					ItemKeyInventory itemKeyInventory = inventoryManager.getItemKeyInventory(
//							task.getSrcLoc().getWarehouse(), task.getItemKey());
					
//					Inventory inventory = itemKeyInventory.getInventoryWithException(task.getSrcLoc(), 
//							task.getPackageUnit(), task.getSrcLP(),null, task.getInventoryStatus(), 
//							task.getStorageDate(), task.getSOI());
					
					inventory.unallocate(quantity, null, null);

					if (task.getPlanQuantityMU()== 0) {
						ts.add(task);
					}
				}
				detail.getTasks().removeAll(ts);
			}
		}
	}
	
	
	@SuppressWarnings("unchecked")
	public void preAllocate(ProcessDocBOMDetail bomDetail, Double quantity) {
    	Warehouse warehouse = bomDetail.getAbstractMoveDoc().getWarehouse();
    	Item item = bomDetail.getItem();
    	NewLotInfo lotInfo = bomDetail.getNewLotInfo() == null ? new NewLotInfo() : bomDetail.getNewLotInfo();
    	itemManager.formatNewLotInfo(lotInfo);
    	String lot = "";
    	String code = bomDetail.getAbstractMoveDoc().getCode();
		
    	//批次属性匹配(是否按照批次属性严格匹配)
    	
    	StringBuffer sb = new StringBuffer();
    	String hql =sb.append("SELECT new com.dev.swms.server.model.shipping.LotQuantity(inventory.itemKeyInventory.itemKey.lot,")
			.append("SUM(inventory.qtyOfMasterPack)) ")
			.append("FROM Inventory inventory ")
			.append("WHERE inventory.itemKeyInventory.warehouse.id = :warehouseId ")
			.append(" AND inventory.itemKeyInventory.itemKey.item.id = :itemId")
			.append(" AND (" )
			.append(NewLotInfoParser.decryptStringOfLot("propC1",lotInfo.getPropC1()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC2",lotInfo.getPropC2()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC3",lotInfo.getPropC3()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC4",lotInfo.getPropC4()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC5",lotInfo.getPropC5()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC6",lotInfo.getPropC6()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC7",lotInfo.getPropC7()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC8",lotInfo.getPropC8()))
			.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC9",lotInfo.getPropC9()))
			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN1",lotInfo.getPropN1()))
			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN2",lotInfo.getPropN2()))
			.append(" AND ").append(NewLotInfoParser.decryptDoubleOfLot("propN3",lotInfo.getPropN3()))
			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD1",lotInfo.getPropD1()))
			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD2",lotInfo.getPropD2()))
			.append(" AND ").append(NewLotInfoParser.decryptDateOfLot("propD3",lotInfo.getPropD3()))
			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC1",lotInfo.getPropL1()))
			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC2",lotInfo.getPropL2()))
			.append(" AND ").append(NewLotInfoParser.decryptLongStringOfLot("propLC3",lotInfo.getPropL3()))
			.append(" ) ")
			.append(" AND (inventory.status is null or inventory.status = '')")
			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
			.append(" AND inventory.location.type IN ('STORAGE','SHIP','READY') ")
			.append(" GROUP BY inventory.itemKeyInventory.itemKey.lot")
			.append(" ORDER BY SUM(inventory.qtyOfMasterPack) DESC").toString();    		
    		
		List<LotQuantity> results = this.commonDao.findByQuery(hql, 
			new String[] {"warehouseId", "itemId"},
			new Object[] {warehouse.getId(), item.getId()});

        Double inventoryQty = 0D;
        if (results != null && results.size() > 0) {
        	//提取批次号并计算可预分配库存总数量
        	for (int i=0;i<results.size();i++) {
            	if (StringUtils.isEmpty(lot)) {
                	lot = String.valueOf(results.get(i).getLot());
            	}
        		inventoryQty += results.get(i).getQuantity();
        	}
        }
        if (inventoryQty <= 0) {
        	return;
        }
        Double preAllocatedQty = (Double) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateQtyByCondition", 
        		new String[] {"warehouseId", "itemId", "lot"},
        		new Object[] {warehouse.getId(), item.getId(), lot});
        if (preAllocatedQty == null) {
        	preAllocatedQty = 0D;
        }
		//库存数量不足，按可用库存分配
        if ((preAllocatedQty + quantity) > inventoryQty) {
        	quantity = (inventoryQty - preAllocatedQty);
    		//如果可预分配数量小于0，返回错误信息
    		if (quantity <= 0) {
    			return;
    		}
    	}
    	//检查预分配数量
    	
    	//检查是否有重复的预分配记录
    	PreAllocate preAllocate = (PreAllocate) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateByUK", new String[] {"code", "warehouseId", "itemId", "lot"}, new Object[] {code, warehouse.getId(), item.getId(), lot});
    	if (preAllocate == null) {
        	preAllocate = EntityFactory.getEntity(PreAllocate.class);
        	preAllocate.setCode(code);
        	preAllocate.setWarehouse(warehouse);
        	preAllocate.setItem(bomDetail.getItem());
        	preAllocate.setLot(lot);
    	}
    	preAllocate.preAllocate(quantity);
    	this.commonDao.store(preAllocate);
    	
    	bomDetail.preAllocate(lot, quantity);
	}


	public void unPreAllocate(ProcessDocBOMDetail bomDetail, Double quantity) {
    	Warehouse warehouse = bomDetail.getAbstractMoveDoc().getWarehouse();
    	Item item = bomDetail.getItem();
    	String lot = bomDetail.getPreAllocatedLot();
    	String code = bomDetail.getCode();
    	Double unPreAllocateQty = (bomDetail.getPreAllocatedQuantity() - bomDetail.getAllocatedQuantity());
    	if (quantity == 0) {
    		return;
    	}
    	if (quantity > unPreAllocateQty) {
    		throw new BusinessException("unPreAlloate.quantity.error");
    	}	
		//发货单明细取消预分配
    	bomDetail.unPreAllocate(quantity);
		//修改预分配表
    	PreAllocate preAllocate = (PreAllocate) this.commonDao.findByNamedQueryUniqueResult("getPreAllocateByUK", new String[] {"code", "warehouseId", "itemId", "lot"}, new Object[] {code, warehouse.getId(), item.getId(), lot});
		if (preAllocate == null) {
			throw new BusinessException("preAllocate.match.none");
		} else {
			//如果取消预分配后记录的预分配数量为0，则删除该预分配记录
			preAllocate.unPreAllocate(quantity);
			if (preAllocate.getPreAllocatedQuantity() == 0) {
				this.commonDao.delete(preAllocate);
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	public void manualAllocate(AbstractMoveDocDetail moveDocDetail, Map inventories) {
		AbstractMoveDoc pickTicket = moveDocDetail.getAbstractMoveDoc();
		Double unallocateQty = moveDocDetail.getUnallocateQuantity();
		if (unallocateQty <= 0) {
			return;
		}
		for (Object obj : inventories.keySet()) {
			Inventory inventory = commonDao.load(Inventory.class, (Long) obj);
			if(inventory.getStatus().equals("不可用")){
				throw new BusinessException("库存为不可用，不能分配！");
			}
			Double quantity = Double.valueOf(inventories.get(obj).toString());
			if(quantity <= 0){
				continue;
			}

			//待分配数量(转换为基本单位数量)
			quantity = quantity*inventory.getPackageUnit().getConvertFigure();
			if (quantity > inventory.getAvaliableQuantity()) {
				quantity = inventory.getAvaliableQuantity();
			}

			if (quantity > unallocateQty) {
				quantity = unallocateQty;
			}
			unallocateQty -= quantity;
			
			
			pickTicket.allocate(null,moveDocDetail, inventory, quantity);
			inventory.allocate(quantity, null, null);
			
			if (unallocateQty <= 0) {
				return;
			}
		}
	}

	public String allocate(Long pickTicketId, Long waveDocId, Long moveDocId, 
			Collection<AbstractMoveDocDetail> details) {
		warehouseId = WarehouseHolder.getWarehouse().getId().longValue();
		synchronized (warehouseId) {
			String errorMsg = "";
			if (pickTicketId != null) {
				String applyCode = "";
				Structure company = null;
				PickTicket pickTicket = commonDao.load(PickTicket.class, pickTicketId);
				if ((PickTicketStatus.PREALLOCATE.equals(pickTicket.getStatus())
						|| (PickTicketStatus.ACTIVE.equals(pickTicket.getStatus()))// && !pickTicket.getCompany().getCompanyWorkRule().isInvSubscribe())
						|| PickTicketStatus.ALLOCATE.equals(pickTicket.getStatus())
						|| PickTicketStatus.PICKUP.equals(pickTicket.getStatus())
						|| PickTicketStatus.SHIP_PART.equals(pickTicket.getStatus()))
						&& pickTicket.getOrderQuantity() > pickTicket.getAllocatedQuantity()) {
					errorMsg += allocate(pickTicket);
					if (StringUtils.isEmpty(applyCode)) {
						applyCode = pickTicket.getApplyDoc() == null ? "" : pickTicket.getApplyDoc();
					}
					if (company == null) {
						company = pickTicket.getCompany();
					}
				}
				if (!StringUtils.isEmpty(applyCode)) {
					updateMoveDocQuantiy(applyCode, warehouseId, company.getId());
				}
			} else if (waveDocId != null) {
				WaveDoc waveDoc = commonDao.load(WaveDoc.class, waveDocId);
				if (WaveDocStatus.ACTIVE.equals(waveDoc.getStatus())||WaveDocStatus.ALLOCATE.equals(waveDoc.getStatus())||WaveDocStatus.OPEN.equals(waveDoc.getStatus())) {
					if (waveDoc.getWaveDocDetails() != null || waveDoc.getWaveDocDetails().size() > 0) {
						errorMsg += allocate(waveDoc);
					}
				}
			} else if (moveDocId != null) {
				MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
				if (MoveDocStatus.OPEN.equals(moveDoc.getStatus())) {
					errorMsg += allocate(moveDoc);
				}
			} else if (details != null) {
				errorMsg += allocateInventoryForPickItemRule(details);
			}
			
			return errorMsg;
		}
	}
	
	public String preAllocate(List<Long> pickTicketIds) {
		String errorMsg = "";
		for(Long pickTicketId:pickTicketIds){
			if (pickTicketId != null) {
				PickTicket pickTicket = commonDao.load(PickTicket.class, pickTicketId);
				if (PickTicketStatus.ACTIVE.equals(pickTicket.getStatus()) 
						|| PickTicketStatus.SHIP_PART.equals(pickTicket.getStatus())){
					//如果发货单的货主作业规则中是否预约发货=false，则不进行预分配，直接自动填写预分配数量
					if(!pickTicket.getCompany().getCompanyWorkRule().isInvSubscribe()){
						for(PickTicketDetail detail : pickTicket.getPickTicketDetails()){
							detail.setPreAllocatedQuantity(detail.getOrderQtyOfMasterUnit());
						}
					}else{
						//拣货分配同时进行预分配，如果预分配失败则不进行拣货分配
						if (pickTicket.getPickTicketDetails() != null || pickTicket.getPickTicketDetails().size() > 0) {
							//preAllocate(pickTicket.getPickTicketDetails());
							prePlanAllocate(pickTicket.getPickTicketDetails());
						}
						if (pickTicket.getPreAllocatedQuantity() <pickTicket.getOrderQuantity()) {
							errorMsg += pickTicket.getCode() + "预分配失败,库存不足;";
							break;
							//return errorMsg;
						}
					}
				}
			}
		}
		if(errorMsg!=null&&!errorMsg.equals("")){
			String code=bussinessCodeManager.generateDayCode("",3);
			for (Long pickTicketId : pickTicketIds) {
				PickTicket pickTicket = commonDao.load(PickTicket.class, pickTicketId);
				pickTicket.setRelatedBill2(code+"预分配失败,库存不足");
				this.commonDao.store(pickTicket);
			}
		}
		return errorMsg;
	}
		
	
	private void updateMoveDocQuantiy(String applyCode, Long warehouseId,
			Long companyId) {
		String hql = "FROM MoveDoc moveDoc WHERE moveDoc.status = 'OPEN' " +
			" AND moveDoc.code = '" + applyCode + "'" +
			" AND moveDoc.billType.code = '" + MoveDoc.MV_SUPPLY + "'" +
			" AND moveDoc.warehouse.id = " + warehouseId+
			" AND moveDoc.company.id = " + companyId;
		
		MoveDoc moveDoc = (MoveDoc) commonDao.findByQueryUniqueResult(hql, new String[]{}, new Object[]{});
		
		if (moveDoc != null) {
			double quantity = 0;
			for (MoveDocDetail detail : moveDoc.getDetails()) {
				detail.setPlanQuantityOfMU(detail.getPlanQuantity() * detail.getPackageUnit().getConvertFigure());
				quantity += detail.getPlanQuantityOfMU();
			}
			moveDoc.setPlanQuantity(quantity);
		}
	}
	
	private String allocate(AbstractMoveDoc moveDoc) {
		String errorMsg = "";
		//try{
		    String code=moveDoc.getCode();
		    List<Task> ts=this.commonDao.findByQuery("select distinct(bhCode) from Task t where t.billCode='"+code+"'");
		    code=code+"-"+ts.size();
			String allocateInfo = allocateInventoryForPickItemRule_New(code,moveDoc.getAbstractMoveDocDetails());
			if (moveDoc.getOrderQuantity() <= moveDoc.getAllocatedQuantity()) {
				errorMsg += moveDoc.getCode() + "整单分配成功;";
			} else if (moveDoc.getAllocatedQuantity()-moveDoc.getPickedQuantity() > 0) {
				errorMsg += moveDoc.getCode() + "部分分配成功[" + allocateInfo + "];";
			} else { 
				errorMsg += moveDoc.getCode() + "分配失败[" + allocateInfo + "];";
			}
		//}catch(Exception e){
		//	e.printStackTrace();
		//	errorMsg += moveDoc.getCode() + " 分配失败[" + e.getMessage() + "];";
		//}
		return errorMsg;
	}
	
	@SuppressWarnings("unchecked")
	private void createSupplyDoc(Warehouse warehouse, Structure company, 
			List<AbstractMoveDocDetail> details) {
		String hql = "FROM MoveDoc moveDoc WHERE moveDoc.status = 'OPEN' " +
				"AND moveDoc.billType.code = '" + MoveDoc.MV_SUPPLY + 
				"' AND moveDoc.warehouse.id = " +
				warehouse.getId()+" AND moveDoc.company.id = " + company.getId();
		
		List<MoveDoc> moveDocs = commonDao.findByQuery(hql);
		MoveDoc moveDoc = null;
		if (moveDocs != null && moveDocs.size() > 0) {
			moveDoc = moveDocs.get(0);
		} else {
			BillType billType = (BillType) this.commonDao
					.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
				new String[] { "companyId", "code" },
				new Object[] {company.getId(), MoveDoc.MV_SUPPLY });
			
			moveDoc = new MoveDoc();		
			moveDoc.setWarehouse(warehouse);
			moveDoc.setStatus(MoveDocStatus.OPEN);
			moveDoc.setCreateDate(new Date());
			moveDoc.setUserTracking();
			moveDoc.setCompany(company);
			moveDoc.setCode(bussinessCodeManager.getCodeByBillType(billType,WarehouseHolder.getWarehouse().getId()));
			//设置单据类型
			moveDoc.setBillType(billType);
		}
		
		for (AbstractMoveDocDetail detail : details) {
			// 得到具体商品的批次属性
			ItemKey itemKey = itemManager.getItemKey(new ItemKey(
					"", detail.getItem(), new LotInfo(), null, null,null), Boolean.FALSE,null);
			double quantity = detail.getUnallocateQuantity();
			
			if (moveDoc.getDetails() == null) {
				moveDoc.setDetails(new HashSet<MoveDocDetail>());
			}
			
			MoveDocDetail mdd = this.generateMoveDocDetail(moveDoc, null, null, 
					null, null, itemKey, detail.getNewLotInfo(),
					itemKey.getItem().getPackageUnitByLineNo(2), quantity,
					Inventory.STATUS_VALID, null, "");
			//更新单据及其明细上的补货标识（对应补货单号）
			detail.setApplyDoc(moveDoc.getCode());
			detail.setApplyDocDetailId(mdd.getId());
			detail.getAbstractMoveDoc().setApplyDoc(moveDoc.getCode());
		}
		commonDao.store(moveDoc);
	}
	
	private MoveDocDetail generateMoveDocDetail(MoveDoc moveDoc, Location srcLoc,
			Stock srcLP, Location dstLoc, Stock dstLP, ItemKey itemKey, NewLotInfo newLotInfo,
			PackageUnit packageUnit, double quantity, String status, Date storageDate, String SOI) {
		MoveDocDetail detail = EntityFactory.getEntity(MoveDocDetail.class);
		detail.setMoveDoc(moveDoc);
		detail.setItemKey(itemKey);
		detail.setNewLotInfo(newLotInfo);
		detail.setPackageUnit(packageUnit);
		detail.setSrcLoc(srcLoc);
		detail.setSrcLP(srcLP);
		detail.setSrcLPCode(srcLP==null?null:srcLP.getLP());
		detail.setDstLoc(dstLoc);
		detail.setDstLP(dstLP);
		detail.setDstLPCode(dstLP==null?null:dstLP.getLP());
		detail.setInventoryStatus(status);
		detail.setStorageDate(storageDate);
		detail.setSOI(SOI);
		for (MoveDocDetail o : moveDoc.getDetails()) {
			if (o.equals(detail)) {
				o.add(quantity);
				return o;
			}
		}
		
		moveDoc.getDetails().add(detail);
		detail.add(quantity);
		commonDao.store(moveDoc);
		commonDao.store(detail);
		return detail;
	}

	//------------------------------------------------------------------------------------------------------
	/**拣货分配算法：
	 *  1、未定义货主和收货人规则时，默认是不允许多发、允许拆托盘和包装；
			如果是混托且不拆托，不参与分配
	 *  3、要整托、整包装、允许多发：
	 		直接分配，直到分配足够（不拆托、不拆包装）
	 *  4、要整托、整包装、不允许多发：
	 		检查待分配数量是否大于整托或者整包装数，只有大于等于的时候才分配；
	 *  5、整托、非整包装、允许多发
	 		托盘整托直接分配；托盘分配不足时，对散货分配，允许拆包装分配，分够数量为止；
	 *  6、整托、非整包装、不允许多发
	 		分配托盘库存数量小于等于待分配数量；
	 		托盘分配不足时，对散货分配，允许拆包装分配，分够数量为止
－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－－
	先找整托数量小于等于待分配数量的托盘，数量不足时找散货，散货也不足时再拆托盘
	 *  7、非整托、整包装、允许多发：
			如果整包装数量大于等于待分配数量，则允许分配整包装（不拆包装）
	 *  8、非整托、整包装、不允许多发
	 		如果整包装数量小于等于待分配数量才分配，不允许拆包装
   	 *  9、非整托、非整包装、允许多发/不允许多发：
   			分够为止
   			
     *	如果托盘是混托，且不允许拆托盘，则不能分配该库存
     *	如果是波次分配，则不允许多发
	 */
	@SuppressWarnings("unchecked")
	public double allocateInventory(String bhCode,Collection<Inventory> inventories, AbstractMoveDocDetail moveDocDetail) {
    	AbstractMoveDoc moveDoc = moveDocDetail.getAbstractMoveDoc();
    	double totalPickQty = 0.0;
    	boolean isShipLimit = false;//是否允许多发
    	
    	if(moveDocDetail instanceof PickTicketDetail){
    		PickTicketDetail detail = (PickTicketDetail)moveDocDetail;
    		if(detail.getPickTicket().getCustomer()!=null){
    			isShipLimit = detail.getPickTicket().getCustomer().isBeShipLimit();
    		}
    	} else if (moveDocDetail instanceof ProcessDocBOMDetail) {
    		//加工单允许多拣
    		isShipLimit = true;
    	}
    	
		//不能拆托分配、不能拆包装分配
//		if(!moveDocDetail.getItem().getCompany().isBeAllowedSplitLPForAllocate() && !moveDocDetail.getItem().getCompany().isBeAllowedSplitPUForAllocate()){
			totalPickQty = allocateInventoryYesYes(bhCode,inventories,moveDocDetail,isShipLimit);
//		}
//		//不能拆托分配、能拆包装分配
//		if(!moveDocDetail.getItem().getCompany().isBeAllowedSplitLPForAllocate() && moveDocDetail.getItem().getCompany().isBeAllowedSplitPUForAllocate()){
//			totalPickQty = allocateInventoryYesNo(inventories,moveDocDetail,isShipLimit);
//		}
//		//能拆托分配、不能拆包装分配
//		if(moveDocDetail.getItem().getCompany().isBeAllowedSplitLPForAllocate() && !moveDocDetail.getItem().getCompany().isBeAllowedSplitPUForAllocate()){
//			totalPickQty = allocateInventoryNoYes(inventories,moveDocDetail,isShipLimit);
//		}
//		//能拆托分配、能拆包装分配
//		if(moveDocDetail.getItem().getCompany().isBeAllowedSplitLPForAllocate() && moveDocDetail.getItem().getCompany().isBeAllowedSplitPUForAllocate()){
//			totalPickQty = allocateInventoryNoNo(inventories,moveDocDetail);
//		}
		
    	return totalPickQty;
	}
	
	/**
	 *  3、要整托、整包装、允许多发：
	 		直接分配，直到分配足够（不拆托、不拆包装）
	 *  4、要整托、整包装、不允许多发：
	 		检查待分配数量是否大于整托或者整包装数，只有大于等于的时候才分配；
	 	如果允许多发，则先保存因为托盘数量大于待分配数量而跳过的托盘库存，在最后仍然没有分配完的情况下，在对跳过的库存进行分配
	 * @param inventories
	 * @param moveDocDetail
	 * @param isShipLimit:是否允许多发
	 * @return
	 */
	public double allocateInventoryYesYes(String bhCode,Collection<Inventory> inventories, AbstractMoveDocDetail moveDocDetail,boolean isShipLimit) {
    	AbstractMoveDoc moveDoc = moveDocDetail.getAbstractMoveDoc();
    	double totalPickQty = 0.0;
    	List<Inventory> skipInventorys = new ArrayList<Inventory>();
    	for(Inventory inventory : inventories){
    		String errmsg = "";
        	//TODO: 如果库存对应库位不是普通货架，当第一个托盘分配失败时，不能提取后面的托盘进行分配
            
            if (inventory.getAvaliableQuantity() <= 0.0) {
                continue;
            }
            if ((!StringUtils.isEmpty(inventory.getStatus())&&!inventory.getStatus().equals("非破损"))
					|| inventory.getLocation().bePickLock()) {
            	continue;
            }
            //判断库存包装与单据明细包装是否匹配
            //double quantity = 0;
            //计算要分配的整包装数量
            //发货单  --- 是否允许多发
            double pickedQuantity = 0.0;
            	pickedQuantity = moveDocDetail.getUnallocateQuantity();
            if (pickedQuantity > 0) {
        		if (moveDocDetail instanceof MoveDocDetail 
        				&& ((MoveDocDetail) moveDocDetail).getDstLoc() == null) {
        			//如果补货计划没有指定目标库位，则需要同时做上架分配
        			errmsg += putawayAllocator.allocateByDetailAndInventory((MoveDocDetail) moveDocDetail, inventory, pickedQuantity);
        		} else {
//        			if(inventory.getLP()!=null){
//        				if(!isMixLP(inventories,inventory)){//如果不是混托，则任意拣货.
//        					if(pickedQuantity>=inventory.getAvaliableQuantity()){
//        						pickedQuantity = inventory.getAvaliableQuantity();//如果拣货数量不满整托或者整个包装，则分配整托或者整个包装
//            					inventory.allocate(pickedQuantity, null, null);
//                    			moveDoc.allocate(moveDocDetail, inventory, pickedQuantity);
//                    			totalPickQty += pickedQuantity;
//        					}else{
//        						if(isShipLimit)//如果允许多发，则保存因为托盘数量过大而跳过的库存，用于再分配
//        							skipInventorys.add(inventory);
//        					}
//            			}
//        			}else{
        				pickedQuantity = getQuantityForPkg(pickedQuantity,inventory.getAvaliableQuantity(),inventory.getPackageUnit(), isShipLimit);
        				if (moveDocDetail instanceof WaveDocDetail ){
        					Item item=moveDocDetail.getItem();
        					if(item.getSuggest()>0||item.getCompany().getCode().equals(CompanyCode.HLX)){
        						double ca=moveDocDetail.getItem().getCAcoefficient()==null?1:moveDocDetail.getItem().getCAcoefficient();
        						if(!item.getCompany().getCode().equals(CompanyCode.HLX)){
        							ca=ca*item.getSuggest();
        						}
        						if(inventory.getAvaliableQuantity()>ca){
        							int xs=(int) Math.ceil(pickedQuantity/ca);
        							pickedQuantity=ca*xs;
        							if(pickedQuantity>inventory.getAvaliableQuantity()){
        								pickedQuantity=inventory.getAvaliableQuantity();
        							}
        						}else{
        							pickedQuantity=inventory.getAvaliableQuantity();
        						}
        					}else{
        						pickedQuantity=inventory.getAvaliableQuantity();
        					}
        				}
        				inventory.allocate(pickedQuantity, null, null);
            			moveDoc.allocate(bhCode,moveDocDetail, inventory, pickedQuantity);
            			totalPickQty += pickedQuantity;
//        			}
        		}
            }
            if(moveDocDetail.getUnallocateQuantity() <= 0){
                return totalPickQty;
            }
    	}
    	//如果允许多发，而且有库存跳过没有分配，并且没有分配够，则对跳过的库存进行再分配，必须是整托分配
    	if(isShipLimit){
    		for(Inventory inv:skipInventorys){
    			double alloQty = 0.0;
    			alloQty = inv.getAvaliableQuantity();
    			inv.allocate(alloQty, null, null);
    			moveDoc.allocate(bhCode,moveDocDetail, inv, alloQty);
    			totalPickQty += alloQty;
    			if(moveDocDetail.getUnallocateQuantity() <= 0){
                    return totalPickQty;
                }
    		}
    	}
    	return totalPickQty;
	}
	/**
	 * 5、整托、非整包装、允许多发
	 		托盘整托直接分配；托盘分配不足时，对散货分配，允许拆包装分配，分够数量为止；
	 * 6、整托、非整包装、不允许多发
	 		分配托盘库存数量小于等于待分配数量；
	 		托盘分配不足时，对散货分配，允许拆包装分配，分够数量为止
	 		
	   如果允许多发，则先保存因为托盘数量大于待分配数量而跳过的托盘库存，在最后仍然没有分配完的情况下，在对跳过的库存进行分配
	 * @param inventories
	 * @param moveDocDetail
	 * @param isShipLimit:是否允许多发
	 * @return
	 */
	public double allocateInventoryYesNo(Collection<Inventory> inventories, AbstractMoveDocDetail moveDocDetail,boolean isShipLimit) {
    	AbstractMoveDoc moveDoc = moveDocDetail.getAbstractMoveDoc();
    	double totalPickQty = 0.0;
    	List<Inventory> skipInventorys = new ArrayList<Inventory>();
    	String errmsg = "";
    	for(Inventory inventory : inventories){
        	//TODO: 如果库存对应库位不是普通货架，当第一个托盘分配失败时，不能提取后面的托盘进行分配
            double pickedQuantity = 0.0;
            if (inventory.getAvaliableQuantity() <= 0.0) {
                continue;
            }
            if (!StringUtils.isEmpty(inventory.getStatus())
					|| inventory.getLocation().bePickLock()) {
            	continue;
            }
            //判断库存包装与单据明细包装是否匹配
            //double quantity = 0;
            //计算要分配的整包装数量
            //发货单  --- 是否允许多发
            pickedQuantity = moveDocDetail.getUnallocateQuantity();
            
            if (pickedQuantity > 0) {
        		if (moveDocDetail instanceof MoveDocDetail 
        				&& ((MoveDocDetail) moveDocDetail).getDstLoc() == null) {
        			//如果补货计划没有指定目标库位，则需要同时做上架分配
        			errmsg += putawayAllocator.allocateByDetailAndInventory((MoveDocDetail) moveDocDetail, inventory, pickedQuantity);
        		} else {
        			if(inventory.getLP()!=null){
        				if(!isMixLP(inventories,inventory)){//如果不是混托，则任意拣货.
        					if(inventory.getAvaliableQuantity()<=pickedQuantity){
        						pickedQuantity = inventory.getAvaliableQuantity();//如果拣货数量不满整托或者整个包装，则分配整托或者整个包装
            					inventory.allocate(pickedQuantity, null, null);
                                moveDoc.allocate(null,moveDocDetail, inventory, pickedQuantity);
                                totalPickQty += pickedQuantity;
        					}else{
        						if(isShipLimit)//如果允许多发，则保存因为托盘数量过大而跳过的库存，用于再分配
        							skipInventorys.add(inventory);
        					}
            			}
        			}else{
        				if(pickedQuantity>=inventory.getAvaliableQuantity()){
        					pickedQuantity = inventory.getAvaliableQuantity();
        				}
        				inventory.allocate(pickedQuantity, null, null);
                        moveDoc.allocate(null,moveDocDetail, inventory, pickedQuantity);
                        totalPickQty += pickedQuantity;
        			}
        		}
            }
            if(moveDocDetail.getUnallocateQuantity() <= 0){
                return totalPickQty;
            }
    	}
    	
//    	如果允许多发，而且有库存跳过没有分配，并且没有分配够，则对跳过的库存进行再分配，必须是整托分配
    	if(isShipLimit){
    		for(Inventory inv:skipInventorys){
    			inv.allocate(inv.getAvaliableQuantity(), null, null);
    			moveDoc.allocate(null,moveDocDetail, inv, inv.getAvaliableQuantity());
    			totalPickQty += inv.getAvaliableQuantity();
    			if(moveDocDetail.getUnallocateQuantity() <= 0){
                    return totalPickQty;
                }
    		}
    	}
    	return totalPickQty;
	}
	/**
	 *7、非整托、整包装、允许多发：
	 		如果整包装数量大于等于待分配数量，则允许分配整包装（不拆包装）
	 *8、非整托、整包装、不允许多发
	 		如果整包装数量小于等于待分配数量才分配，不允许拆包装
	 * @param inventories
	 * @param moveDocDetail
	 * @param isShipLimit:是否允许多发
	 * @return
	 */
	public double allocateInventoryNoYes(Collection<Inventory> inventories, AbstractMoveDocDetail moveDocDetail, boolean isShipLimit) {
    	AbstractMoveDoc moveDoc = moveDocDetail.getAbstractMoveDoc();
    	double totalPickQty = 0.0;
    	String errmsg = "";
    	for(Inventory inventory : inventories){
        	//TODO: 如果库存对应库位不是普通货架，当第一个托盘分配失败时，不能提取后面的托盘进行分配
            double pickedQuantity = 0.0;
            if (inventory.getAvaliableQuantity() <= 0.0) {
                continue;
            }
//            if (!StringUtils.isEmpty(inventory.getStatus())
//					|| inventory.getLocation().isPickLock()) {
//            	continue;
//            }
            //判断库存包装与单据明细包装是否匹配
            //double quantity = 0;
            //计算要分配的整包装数量
            //发货单  --- 是否允许多发
            pickedQuantity = moveDocDetail.getUnallocateQuantity();
            
            if (pickedQuantity > 0) {
        		if (moveDocDetail instanceof MoveDocDetail 
        				&& ((MoveDocDetail) moveDocDetail).getDstLoc() == null) {
        			//如果补货计划没有指定目标库位，则需要同时做上架分配
        			errmsg += putawayAllocator.allocateByDetailAndInventory((MoveDocDetail) moveDocDetail, inventory, pickedQuantity);
        		} else {
        			if(inventory.getLP()!=null){
        				if(pickedQuantity>=inventory.getAvaliableQuantity()){
        					pickedQuantity = inventory.getAvaliableQuantity();
        				}
        				inventory.allocate(pickedQuantity, null, null);
                        moveDoc.allocate(null,moveDocDetail, inventory, pickedQuantity);
                        totalPickQty += pickedQuantity;
        			}else{
        				pickedQuantity = getQuantityForPkg(pickedQuantity,inventory.getAvaliableQuantity()/inventory.getPackageUnit().getConvertFigure(),inventory.getPackageUnit(), isShipLimit);
        				inventory.allocate(pickedQuantity, null, null);
                        moveDoc.allocate(null,moveDocDetail, inventory, pickedQuantity);
                        totalPickQty += pickedQuantity;
        			}
        		}
            }
            if(moveDocDetail.getUnallocateQuantity() <= 0){
                return totalPickQty;
            }
    	}
    	return totalPickQty;
	}
	/**
	 *9、非整托、非整包装、允许多发/不允许多发：
	 		分够为止
	 * @param inventories
	 * @param moveDocDetail
	 * @return
	 */
	public double allocateInventoryNoNo(Collection<Inventory> inventories, AbstractMoveDocDetail moveDocDetail) {
    	AbstractMoveDoc moveDoc = moveDocDetail.getAbstractMoveDoc();
    	double totalPickQty = 0.0;
    	String errmsg = "";
    	for(Inventory inventory : inventories){
        	//TODO: 如果库存对应库位不是普通货架，当第一个托盘分配失败时，不能提取后面的托盘进行分配
            double pickedQuantity = 0.0;
            if (inventory.getAvaliableQuantity() <= 0.0) {
                continue;
            }
            if (!StringUtils.isEmpty(inventory.getStatus())
					|| inventory.getLocation().bePickLock()) {
            	continue;
            }
            //判断库存包装与单据明细包装是否匹配
            //double quantity = 0;
            //计算要分配的整包装数量
            //发货单  --- 是否允许多发
            pickedQuantity = moveDocDetail.getUnallocateQuantity();
            
            if (pickedQuantity > 0) {
        		if (moveDocDetail instanceof MoveDocDetail 
        				&& ((MoveDocDetail) moveDocDetail).getDstLoc() == null) {
        			//如果补货计划没有指定目标库位，则需要同时做上架分配
        			errmsg += putawayAllocator.allocateByDetailAndInventory((MoveDocDetail) moveDocDetail, inventory, pickedQuantity);
        		} else {
        			if(pickedQuantity>=inventory.getAvaliableQuantity()){
    					pickedQuantity = inventory.getAvaliableQuantity();
    				}
    				inventory.allocate(pickedQuantity, null, null);
                    moveDoc.allocate(null,moveDocDetail, inventory, pickedQuantity);
                    totalPickQty += pickedQuantity;
        		}
            }
            if(moveDocDetail.getUnallocateQuantity() <= 0){
                return totalPickQty;
            }
    	}
    	return totalPickQty;
	}
	/**
	 * 检查库存inv的托盘是否是混托
	 * @param inventories
	 * @param inv
	 * @return
	 */
	private boolean isMixLP(Collection<Inventory> inventories,Inventory inv){
		if(inv.getLP()==null)
			return false;
		for(Inventory tinv:inventories){
			if(inv.getId()!=tinv.getId() 
					&& (tinv.getLP()!=null && inv.getLP().getId()==tinv.getLP().getId())){
				return true;
			}
		}
		return false;
	}
	/**
	 * 当不允许拆包装的时候，取得库存上应该分配的数量；
	 * 例如：计划分配数量为85，单位为“个”，库存数量100，单位“箱”；每箱10个；则应该分配90个（9箱）
	 * @param orderQty:待分配数量（最小包装单位数量）
	 * @param invQty
	 * @param newUnit
	 * @param isSplit:true:允许多发;false: 不允许多发
	 * @return
	 */
	private double getQuantityForPkg(double orderQty,double invQty,PackageUnit invUnit,boolean isSplit){
		int figure=1;//invUnit.getConvertFigure()
		if(isSplit){
			if(Math.ceil(orderQty/figure)<=invQty){
				return Math.ceil(orderQty/figure)*figure;
			}else{
				return invQty*figure;
			}
		}else{
			if((Math.floor(orderQty/figure))<=invQty){
				return (Math.floor(orderQty/figure))*figure;
			}else{
				return invQty*figure;
			}
		}
	}
	
	/**
	 * 拣货分配过程
	 * @param moveDocDetails
	 */
	@SuppressWarnings("unchecked")
	private String allocateInventoryForPickItemRule_KAMS(String code,Collection<AbstractMoveDocDetail> moveDocDetails) {
		String errmsg = "";
		Warehouse warehouse = null;
        for(AbstractMoveDocDetail moveDocDetail : moveDocDetails){
        	//如果发货单明细无未分配数量，则忽略
        	System.out.println(moveDocDetail.getItem().getId()+"==="+moveDocDetail.getItem().getCode()+"==="+moveDocDetail.getUnallocateQuantity());
        	if (moveDocDetail.getUnallocateQuantity() <= 0) {
        		continue;
        	}
        	String loc_code=null;
        	String loc_type="'STORAGE','TRANSIT'";
        	warehouse = moveDocDetail.getAbstractMoveDoc().getWarehouse();
//        	if(moveDocDetail instanceof PickTicketDetail){//当货品补货位不为空，且零散数量只能从拣货位出
//        		PickTicketDetail d=(PickTicketDetail)moveDocDetail;
//        		warehouse = moveDocDetail.getAbstractMoveDoc().getWarehouse();
//        		loc_type="'STORAGE','TRANSIT'";
//        	}
//        	Boolean bh=Boolean.FALSE;
//        	if(moveDocDetail.getItem().getLocation()!=null){
//        		 bh=Boolean.TRUE;
//        	}
//        	Location dstLoc = moveDocDetail.getAllocateDstLoc();
    		List<Inventory> tempInventories = new ArrayList<Inventory>();
        	double totalQty = 0.0;
	    	Item item = moveDocDetail.getItem();
			NewLotInfo lotInfo = moveDocDetail.getNewLotInfo() == null ? new NewLotInfo() : moveDocDetail.getNewLotInfo();
			String locHql = "";
			//不包含目标库位库存
//			if (dstLoc != null) {
//				locHql += " AND inventory.location.id <> " + dstLoc.getId();
//			}
    			StringBuffer sb = new StringBuffer();
    	    	String hql =sb.append(" FROM Inventory inventory ")
    			.append("WHERE inventory.location.warehouse.id=:warehouseId ")
    			.append("AND inventory.itemKey.item.id = :itemId")
//				.append(" AND ").append(NewLotInfoParser.decryptStringOfLot("propC3",lotInfo.getPropC3()))
    			.append(" AND (inventory.status is null or inventory.status = '' or inventory.status = '非破损')")
    			.append(" AND (inventory.location.countLock is null or inventory.location.countLock = '')")
    			.append(" AND (inventory.location.outLock is null or inventory.location.outLock = '')")
    			.append(" AND (inventory.qtyOfMasterPack - inventory.queuedQuantity) > 0")
    			.append(" AND inventory.location.type in ("+loc_type+")")
    			.append(locHql)
    			.toString();
//    	    	    if(lotInfo.getPropD1()!=null){
//    		    		hql+=" and to_char(inventory.itemKeyInventory.itemKey.lotInfo.propD1,'yyyy-mm-dd')='"+lotInfo.getPropD1()+"'";
//    		    	}
//    		    	if(loc_code!=null){
//    		    		hql+=" and inventory.location.code ='"+loc_code+"'";
//    		    	}
//			     	if(moveDocDetail instanceof WaveDocDetail){
//			     		hql+=" and inventory.location.code !='"+moveDocDetail.getItem().getLocation().getCode()+"'";
//			     	}
    		    	hql+=" order by inventory.location.type desc ";
    		    	hql+=" ,inventory.itemKey.lotInfo.propD2 asc";
    		    	hql+=", (inventory.qtyOfMasterPack - inventory.queuedQuantity) asc";
    		    	hql+=" ,inventory.location.code asc";
    		    	hql+=" ,inventory.location.sortIndex asc";
    		    	System.out.println(item.getId()+"a1==="+new Date());
    	    	tempInventories.addAll(this.commonDao.findByQuery(hql, 
    	    			new String[] {"warehouseId", "itemId"}, 
    	    			new Object[] {warehouse.getId(), item.getId()}));
    	    	System.out.println("a2==="+new Date());
                if (tempInventories.size()>0) {
	                 totalQty += allocateInventory(code,tempInventories, moveDocDetail);
	                 System.out.println("a3==="+new Date());
                if((moveDocDetail.getPreAllocatedQuantity()-moveDocDetail.getAllocatedQuantity())<=0){
                		//break;
                	continue;
                }else{
                	 System.out.println(moveDocDetail.getItem()+"===="+moveDocDetail.getAllocatedQuantity());
                }
        	}
        	
        }
        
        return errmsg;
	}
	
	
	
	
}

