package com.dev.swms.server.service.inventory.pojo;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
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 java.util.Random;
import java.util.Set;

import net.sf.json.JSONObject;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

import com.dev.sequence.service.sequence.SequenceGenerater;
import com.dev.swms.server.model.abstractEntity.Pinfan;
import com.dev.swms.server.model.base.BillType;
import com.dev.swms.server.model.base.Item;
import com.dev.swms.server.model.base.ItemKey;
import com.dev.swms.server.model.base.LPFormat;
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.Structure;
import com.dev.swms.server.model.base.SysCode;
import com.dev.swms.server.model.base.PackageUnit;
import com.dev.swms.server.model.base.Position;
import com.dev.swms.server.model.base.PositionDetail;
import com.dev.swms.server.model.base.Warehouse;
import com.dev.swms.server.model.base.WarehouseArea;
import com.dev.swms.server.model.base.Worker;
import com.dev.swms.server.model.count.CountRecord;
import com.dev.swms.server.model.inventory.EditLotInfoType;
import com.dev.swms.server.model.inventory.Inventory;
import com.dev.swms.server.model.inventory.InventoryLockType;
import com.dev.swms.server.model.inventory.InventoryLog;
import com.dev.swms.server.model.inventory.InventoryLogType;
import com.dev.swms.server.model.inventory.ItemKeyInventory;
import com.dev.swms.server.model.inventory.ProcessDoc;
import com.dev.swms.server.model.inventory.ProductInventory;
import com.dev.swms.server.model.inventory.Stock;
import com.dev.swms.server.model.inventory.StockType;
import com.dev.swms.server.model.inventory.StorageDaily;
import com.dev.swms.server.model.inventory.Task;
import com.dev.swms.server.model.inventory.TaskLog;
import com.dev.swms.server.model.receiving.ASN;
import com.dev.swms.server.model.receiving.MoveDoc;
import com.dev.swms.server.model.receiving.MoveDocDetail;
import com.dev.swms.server.model.receiving.MoveObject;
import com.dev.swms.server.model.receiving.MoveObjectDetail;
import com.dev.swms.server.model.receiving.ReceivedRecord;
import com.dev.swms.server.model.rules.CompanyTransRule;
import com.dev.swms.server.model.rules.CompanyTransRuleDetail;
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.PrintXppRecord;
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.service.sequence.SwmsSequenceDao;
import com.dev.swms.server.service.shipping.PickKamsManager;
import com.dev.swms.server.utils.DateUtil;
import com.dev.swms.server.utils.DoubleUtils;
import com.dev.swms.server.web.filter.WarehouseHolder;

import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;

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;
import com.dev.energy.server.web.security.UserHolder;

/**
 * @author  dev
 */
public class DefaultInventoryManager extends DefaultBaseManager implements InventoryManager,ApplicationContextAware{
	protected final ItemManager itemManager;
	protected final BussinessCodeManager codeManager;
	private static ApplicationContext ac;

	public DefaultInventoryManager(ItemManager manager, BussinessCodeManager manager2) {
		super();
		itemManager = manager;
		codeManager = manager2;
	}
	
	public void setApplicationContext(ApplicationContext arg0) throws BeansException {
		ac = arg0;
	}

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#getItemKeyInventory(com.dev.swms.server.model.base.Warehouse, com.dev.swms.server.model.base.ItemKey)
	 */
	public ItemKeyInventory getItemKeyInventory(Warehouse warehouse, ItemKey itemKey) {
		ItemKeyInventory dbItemKeyInventory = (ItemKeyInventory) commonDao.findByNamedQueryUniqueResult(
				"getItemKeyInventoryByUniqueKey",
				new String[]{"itemKeyId","warehouseId"},
				new Object[]{itemKey.getId(), warehouse.getId()});
		if(dbItemKeyInventory == null){
			dbItemKeyInventory = new ItemKeyInventory();//EntityFactory.getEntity(ItemKeyInventory.class);
			dbItemKeyInventory.setItemKey(itemKey);
			dbItemKeyInventory.setWarehouse(warehouse);
			commonDao.store(dbItemKeyInventory);
		}
		return dbItemKeyInventory;
	}

	/**
	 * 记录库存变动日志---收发货调整
	 * @param logType 业务类型
	 * @param incOrDec 增减类型
	 * @param relatedBill 相关单号
	 * @param location 发生库位
	 * @param lp 发生托盘
	 * @param itemKey 商品批次属性
	 * @param storageDate 存货日期
	 * @param soi 收货单号
	 * @param occurQuantity 发生数量(MU)
	 * @param packageUnit 包装单位
	 * @param status 库存状态
	 * @param referenceLog 相关日志ID
	 * @param description 备注
	 * @param billType 相关单据类型
	 */
	private InventoryLog addInventoryLog(String logType, int incOrDec, String relatedBill, Location location, 
			String zone_code, ItemKey itemKey, Date storageDate, String soi, double occurQuantity, PackageUnit unit, 
			String status, Long referenceLog, String description, BillType billType,WarehouseArea zone) {
		InventoryLog log = new InventoryLog(logType, incOrDec, relatedBill, billType, location, zone_code, itemKey, 
				storageDate, soi, occurQuantity, unit, status, referenceLog, description,zone);
		if(logType.equals(InventoryLogType.PICK_DOWN)){
			if(incOrDec==1){
				List<Location> locs=this.commonDao.findByQuery("from Location l where l.name='待发货区'");
				if(locs.size()>1){
					log.setLocation(locs.get(0));
				}
			}
		}else if(logType.equals(InventoryLogType.SHIPPING)){
			if(incOrDec==-1){
				List<Location> locs=this.commonDao.findByQuery("from Location l where l.name='待发货区'");
				if(locs.size()>1){
					log.setLocation(locs.get(0));
				}
			}
		}
		commonDao.store(log);
		
		return log;
	}

	/**
	 * 保存商品库存---当itemKeyInventory中无库存明细时，要删除itemKeyInventory
	 * @param itemKeyInventory
	 */
	private void storeItemKeyInventory(ItemKeyInventory itemKeyInventory) {
		if (itemKeyInventory.getInventories()!=null && itemKeyInventory.getInventories().size()>0) {
			commonDao.store(itemKeyInventory);
		} else {
			commonDao.delete(itemKeyInventory);
		}
	}

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#receiving(java.lang.Long, com.dev.swms.server.model.base.ItemKey, double, java.lang.Long, java.lang.String)
	 */
	public void receiving(Long locationId, ItemKey itemKey, double quantity, Long packageUnitId, 
			Long zone_id,String barCode,double weight,double volume, String relatedBill, String qualityCode, Date receiveDate, BillType billType,Boolean lock,Boolean reject) {
		Location location = commonDao.load(Location.class, locationId);
		PackageUnit packageUnit = null;//commonDao.load(PackageUnit.class,packageUnitId);
//		Stock stock = (LP == null ? null : commonDao.load(Stock.class, LP));
		//对数量预先做格式化处理，统一小数位数
		//quantity = DoubleUtils.formatByPrecision(quantity, packageUnit.getPrecision());
		if (quantity == 0) {
			return;
		}
		WarehouseArea zone=this.commonDao.load(WarehouseArea.class, zone_id);
		//收货到库存
		Inventory inventory = receiveToInventory(location, itemKey, quantity, packageUnit, 
				zone,  barCode, weight, volume,relatedBill, qualityCode, receiveDate,lock,reject);

//		//更新托盘信息
//		if (stock!=null && stock.getInventoryQty() == 0) {
//			removeLPRelations(stock);
//		}
		//更新库位信息
//		location.refreshTotal();
		String str1=InventoryLogType.RECEIVING;
			if(billType!=null&&billType.getCode().equals("QTRK")) {
				str1=InventoryLogType.RECEIVING_ADJUST;
			}
		//写库存日志
		addInventoryLog(str1, 1, relatedBill, location,zone.getCode(), 
				inventory.getItemKey(), receiveDate, relatedBill, quantity, packageUnit, 
				inventory.getStatus(), null, null, billType,inventory.getZone());
	}
	
	/**
	 * 收货到库存
	 * @param location 收货库位
	 * @param itemKey 收货批次
	 * @param quantity 收货数量（基本单位数量）
	 * @param packageUnit 收货包装
	 * @param LP 托盘
	 * @param relatedBill 相关单号
	 * @param qualityCode 质损代码
	 * @param receiveDate 收货日期
	 * @return 
	 */
	private Inventory receiveToInventory(Location location, ItemKey itemKey,double quantity, 
			PackageUnit packageUnit, WarehouseArea zone, String barCode,double weight,double volume,String relatedBill, 
			String qualityCode, Date receiveDate,Boolean lock,Boolean reject) {
		//锁检查
//		if (location.bePutAwayLock()) {
//			throw new BusinessException("location.locked");
//		}
//		//托盘检查
//		if (LP != null && location.getStowage()!=null&&location.getStowage().getLpLimit()<=0) {
//			throw new BusinessException("location.lpStore.avaliable");
//		}
		//混放检查(存货库位)
//		if (LocationType.STORAGE.equals(location.getType())) {
//			if (!location.beMixAble(itemKey.getItem().getId(), itemKey.getId())) {
//				throw new BusinessException("location.mixCheck.invalid");
//			}
//		}
		
//		Item item = itemKey.getItem();
//		if (item.getDefaultLotRule() != null && item.getDefaultLotRule().getLotRuleComponent().getTrackPropD1()) {
//			if(itemKey.getLotInfo().getPropD1()==null && itemKey.getLotInfo().getPropD2()==null){
//				throw new BusinessException("inventory.oneDateInfo.required");
//			}
//			if(itemKey.getLotInfo().getPropD1()==null){
//				itemKey.setInvaidStart(item); 
//			}
//			if(itemKey.getLotInfo().getPropD2()==null){
//				itemKey.setInvaidEnd(item); 										
//			}
//		}
		//写入供应商的名称到lotInfo
//		if (itemKey.getLotInfo().getPropL1() != null && itemKey.getLotInfo().getPropL1() != 0) {
//			Structure supplier = this.commonDao.load(Structure.class, itemKey.getLotInfo().getPropL1());
//			itemKey.getLotInfo().setPropLC1(supplier.getName());
//		} else {
//			itemKey.getLotInfo().setPropL1(null);
//		}
//		this.commonDao.store(itemKey);
		
//		ItemKeyInventory itemKeyInventory = getItemKeyInventory(location.getWarehouse(), itemKey);
		
		Inventory inventory = this.adjustInventoryAdd(itemKey,zone,location, 
				quantity,qualityCode,lock,reject);
		this.commonDao.store(inventory);
		
		return inventory;
	}
	
	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#receivingAdjust(java.lang.Long, com.dev.swms.server.model.base.ItemKey, double, java.lang.Long, java.util.Date, java.lang.String)
	 */
	public void receivingAdjust(Long locationId, ItemKey itemKey, double quantity, Long packageUnitId, 
			Long LP, String barCode,double weight,double volume,String status, Date storageDate,
			String soi, BillType billType,Boolean lock,Boolean reject) {
		PackageUnit packageUnit =null;// commonDao.load(PackageUnit.class, packageUnitId);
		Location location = commonDao.load(Location.class, locationId);
		Stock stock = (LP == null ? null : commonDao.load(Stock.class, LP));
		if (location.bePutAwayLock()) {
			throw new BusinessException("location.locked");
		}
		//对数量预先做格式化处理，统一小数位数
		int incOrDec = (quantity > 0 ? -1 : 1);
		//quantity = DoubleUtils.formatByPrecision(Math.abs(quantity), packageUnit.getPrecision());

		ItemKeyInventory itemKeyInventory = getItemKeyInventory(location.getWarehouse(), itemKey);
		Inventory inventory =null;
		if (incOrDec == -1) {
			inventory = itemKeyInventory.adjustInventoryRemove(location, 
					quantity, packageUnit, stock, barCode, weight, volume,status, storageDate, soi);
		} else {
			inventory = itemKeyInventory.adjustInventoryAdd(location, 
					quantity, packageUnit, stock, barCode, weight, volume,status, storageDate, soi,lock,reject);
		}
		
		//更新托盘信息
		if (stock!=null && stock.getInventoryQty() == 0) {
			removeLPRelations(stock);
		}
		//更新库位信息
		location.refreshTotal();
		
		storeItemKeyInventory(itemKeyInventory);
		addInventoryLog(InventoryLogType.RECEIVING_ADJUST, incOrDec, soi, location, 
				(stock==null?null:stock.getLP()), inventory.getItemKeyInventory().getItemKey(), storageDate, 
				soi, quantity, packageUnit, inventory.getStatus(), null, null, billType,inventory.getZone());
	}

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#shippingAdjust(java.lang.Long, com.dev.swms.server.model.base.ItemKey, double, java.lang.Long, java.util.Date, java.lang.String)
	 */
	public void shippingAdjust(Long locationId, ItemKey itemKey, double quantity, Long packageUnitId, 
			Long LP, String status, Date storageDate, String soi, String relatedBill, BillType billType, 
			String description,Boolean lock,Boolean reject) {
		String barCode=null;
		double weight=0;
		double volume=0;
		Location location = commonDao.load(Location.class, locationId);
		if (location.bePickLock()) {
			throw new BusinessException("location.locked");
		}
		ItemKeyInventory itemKeyInventory = getItemKeyInventory(location.getWarehouse(), itemKey);
		PackageUnit packageUnit = commonDao.load(PackageUnit.class, packageUnitId);
		Stock stock = (LP == null ? null : commonDao.load(Stock.class, LP));
		//对数量预先做格式化处理，统一小数位数
		int incOrDec = (quantity > 0 ? 1 : -1);
		quantity = DoubleUtils.formatByPrecision(Math.abs(quantity), packageUnit.getPrecision());
		
		Inventory inventory = null;
		if (incOrDec == 1) {
			inventory = itemKeyInventory.adjustInventoryAdd(location, 
					quantity*packageUnit.getConvertFigure(), packageUnit, stock, barCode, weight, volume, status, storageDate, soi,lock,reject);
		} else {
			inventory = itemKeyInventory.adjustInventoryRemove(location, 
					quantity*packageUnit.getConvertFigure(), packageUnit, stock, barCode, weight, volume, status, storageDate, soi);
		}
		
		//更新托盘信息
		if (stock!=null && stock.getInventoryQty() == 0) {
			removeLPRelations(stock);
		}
		//更新库位信息
		location.refreshTotal();

		storeItemKeyInventory(itemKeyInventory);
		addInventoryLog(InventoryLogType.SHIPPING_ADJUST, incOrDec, relatedBill, location, 
				(stock==null?null:stock.getLP()), inventory.getItemKeyInventory().getItemKey(), 
				storageDate, soi, quantity*packageUnit.getConvertFigure(), packageUnit, 
				inventory.getStatus(), null, description, billType,inventory.getZone());
	}
	
	private Inventory adjustInventoryAdd(Location location, ItemKey itemKey, double quantity, 
			PackageUnit packageUnit, Stock stock, String status, Date storageDate, String soi, 
			String logType, String description,	BillType billType, String relatedBill,Boolean lock,Boolean reject) {
		Item item = this.load(Item.class,itemKey.getItem().getId());
		if (item.getDefaultLotRule() != null && item.getDefaultLotRule().getLotRuleComponent().getTrackPropD1()) {
			if (itemKey.getLotInfo().getPropD1() == null && itemKey.getLotInfo().getPropD2() == null){
				throw new BusinessException("inventory.oneDateInfo.required");
			}
			if (itemKey.getLotInfo().getPropD1() == null) {
				itemKey.setInvaidStart(item); 
			}
			if (itemKey.getLotInfo().getPropD2() == null) {
				itemKey.setInvaidEnd(item); 										
			}
		}
		//写入供应商的名称到lotInfo
		if (itemKey.getLotInfo().getPropL1() != null && itemKey.getLotInfo().getPropL1() != 0) {
			Structure supplier = this.commonDao.load(Structure.class, itemKey.getLotInfo().getPropL1());
			itemKey.getLotInfo().setPropLC1(supplier.getName());
		} else {
			itemKey.getLotInfo().setPropL1(null);
		}
		
		Inventory inventory = adjustInventoryAddWithNoLog(location, itemKey, quantity, packageUnit, 
				stock, status, storageDate, soi, description.equals(Inventory.COUNT_ADJUST),lock,reject);
		

		//更新托盘信息
		if (stock!=null && stock.getInventoryQty() == 0) {
			removeLPRelations(stock);
		}
		//更新库位信息
		location.refreshTotal();
		
		if (inventory != null) {
			//盘点库位新增日志时，增减类型统一为1，即使数量小于0
			int incOrDec = (quantity <= 0 ? -1 : 1);
			addInventoryLog(logType, incOrDec, relatedBill, inventory.getLocation(), 
					(stock==null?null:stock.getLP()), inventory.getItemKeyInventory().getItemKey(), 
					storageDate, soi, Math.abs(quantity), inventory.getPackageUnit(), 
					inventory.getStatus(), null, description, billType,inventory.getZone());
		}
		return inventory;
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#modifyInventory(java.lang.Long, double, java.lang.String)
	 */
	public void modifyInventory(Long inventoryId, double packQty, String description) {
//		List<InventoryLog> invs=this.commonDao.findByQuery("from InventoryLog inv where inv.zone.id in (24) and inv.itemKey.pinfan.bonded='课税' "
//				+ " and inv.location.type='SHIP' ");
//		for(InventoryLog l:invs){
//			List<ItemKey> iks=this.commonDao.findByQuery("from ItemKey k where k.pinfan.zone.id=24 and k.item.id="+l.getItemKey().getItem().getId());
//			if(iks.size()>0){
//			ItemKey ik=iks.get(0);
//			l.setItemKey(ik);
////			l.setLocation(ik.getPinfan().getLocation());
//			this.commonDao.store(l);
//			}else{
//				System.out.println("bucunzai"+l.getItemKey().getItem().getCode());
//			}
//		}
//		Map<String,Integer> map=new HashMap<String, Integer>();
////		map.put("1J55017101",	400);
////		map.put("3C08175713",	72 );
////		map.put("3C58104292",	100);
////		map.put("3K06583741",	110);
//		map.put("3N60075231",	400);
////		map.put("RD41163821",	100);
////		map.put("RD45154382",	600);
////		map.put("RD81953711",	80 );
//		
//		for(Map.Entry<String, Integer> m:map.entrySet()){
//			String item_code=m.getKey();
//////			inv.setLocation(inv.getItemKey().getPinfan().getLocation());
//			List<Inventory> inv2=this.commonDao.findByQuery("from Inventory inv where inv.zone.id=21 and inv.itemKey.pinfan.bonded='课税' "
//					+ "and  inv.location.type!='SHIP' and inv.itemKey.item.code='"+m.getKey()+"'");
//			Integer qty=m.getValue();
//			if(inv2.size()>0){
//				Inventory i=inv2.get(0);
//				i.setQtyOfMasterPack(i.getQtyOfMasterPack()+qty);
//				i.setQuantity(i.getQuantity()+qty);
//				i.setQueuedQuantity(i.getQueuedQuantity());
//				this.commonDao.store(i);
//				System.out.println(m.getKey()+"ok");
//			}else{
//				String hql="from Pinfan f where f.item.code='"+item_code+"'";
//				hql+="  and f.zone.id=21";
//				List<Pinfan> pfs=this.commonDao.findByQuery(hql);
//				System.out.println(item_code);
//				Pinfan pf=pfs.get(0);
//				ItemKey key = this.itemManager.getItemKey(new ItemKey("",
//						pf.getItem(), pfs.get(0)), Boolean.TRUE,null);
//				this.commonDao.store(key);
//				Inventory inventory = getInventoryNew(key,pf.getZone(),pf.getLocation(), null);
//				inventory.add(qty,0,0);
//				if (inventory.isNew()) {
//					key.getInventories().add(inventory);
//				}
//				this.commonDao.store(inventory);
//				//创建库存
//				System.out.println(m.getKey()+"bucunzai");
//			}
//			
//		}
		
		Inventory inventory = commonDao.load(Inventory.class, inventoryId);
		if(packQty<inventory.getQueuedQuantity()){
			throw new BusinessException("库存数量必须大于已分配数量！");
		}
		double deltaQty=inventory.getQtyOfMasterPack()-packQty;
		if(deltaQty==0){
			throw new BusinessException("数量无变化");
		}
		double srcQty=inventory.getQtyOfMasterPack();
		inventory.setQuantity(packQty);
		inventory.setQtyOfMasterPack(packQty);
		this.commonDao.store(inventory);
		int incOrDec = (deltaQty<0 ? 1 : -1);
		addInventoryLog(InventoryLogType.INVENTORY_ADJUST, incOrDec, inventory.getZone(), inventory.getLocation(), "库存调整", inventory.getItemKey(),
				Math.abs(deltaQty), null, UserHolder.getUser().getName(), inventory.getId(),  srcQty+"库存调整"+inventory.getQtyOfMasterPack(),description, null, null, inventory.getZzkw());
//		addInventoryLog(InventoryLogType.INVENTORY_ADJUST, incOrDec, "库存调整", inventory.getLocation(), 
//				(inventory.getLP()==null?null:inventory.getLP().getLP()), 
//				inventory.getItemKey(), inventory.getStorageDate(), inventory.getSOI(),	
//				Math.abs(deltaQty), inventory.getPackageUnit(), inventory.getStatus(), null, description, null,inventory.getZone());
		
	}

	private void adjustInventoryUpdate(Inventory inventory, double quantity, String logType, String description) {
		if (inventory.getLocation().beLocked() && !description.equals(Inventory.COUNT_ADJUST)) {
			throw new BusinessException("location.locked");
		}
		
		double oldQuantity = inventory.getQtyOfMasterPack();
		double deltaQty = quantity - oldQuantity;
		if(quantity<inventory.getQueuedQuantity()){
			throw new BusinessException("库存数量必须大于已分配数量！");
		}
		//库存调整
		adjustInventoryUpdateWithNoLog(inventory, quantity);

		//更新托盘信息
		Stock stock = inventory.getLP();
		if (stock!=null && stock.getInventoryQty() == 0) {
			removeLPRelations(stock);
		}
		//更新库位信息
		inventory.getLocation().refreshTotal();

		//库存调整日志记录
		int incOrDec = (oldQuantity > inventory.getQtyOfMasterPack() ? -1 : 1);
		addInventoryLog(logType, incOrDec, null, inventory.getLocation(), 
				(inventory.getLP()==null?null:inventory.getLP().getLP()), 
				inventory.getItemKeyInventory().getItemKey(), inventory.getStorageDate(), inventory.getSOI(),	
				Math.abs(deltaQty), inventory.getPackageUnit(), inventory.getStatus(), null, description, null,inventory.getZone());
	}
	
	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#moveInventory(java.lang.Long, java.lang.Long, double)
	 */
	public void moveInventory(Long srcInventoryId, Long destLocationId, Long dstLP, double quantity, 
			Long packageUnitId, Long taskId, Long workerId) {
		if(destLocationId == null){
			throw new BusinessException("destlocation.not.null");
		}
		Task task = (taskId == null ? null : commonDao.load(Task.class, taskId));
		Worker worker = (workerId == null ? null : commonDao.load(Worker.class, workerId));
		Inventory srcInventory = commonDao.load(Inventory.class, srcInventoryId);
		Location destLocation = commonDao.load(Location.class, destLocationId);
//		//判断目标库位上是否有托盘，有的话则取目标库位上托盘，如果目标库位为补货位，则不需要托盘
//		if(destLocation.getType().equals(LocationType.STORAGE)){
//			List<Inventory> invs=this.commonDao.findByQuery("from Inventory inv where inv.location.id=:locationId",
//					new String[]{"locationId"},new Object[]{destLocationId});
//			if(invs.size()>0){
//				dstLP=invs.get(0).getLP()==null?null:invs.get(0).getLP().getId();
//			}
//		}else if(destLocation.getType().equals(LocationType.TRANSIT)){
//			dstLP=null;
//		}
//		PackageUnit pu = commonDao.load(PackageUnit.class, packageUnitId);
		//对数量预先做格式化处理，统一小数位数
//		quantity = DoubleUtils.formatByPrecision(quantity, pu.getPrecision());
//		Stock stock = (dstLP == null ? null : commonDao.load(Stock.class, dstLP));
		
		//记录源库存数量减少日志
		BillType billType = null;
		String moveDocCode = null;
		String logType=InventoryLogType.MOVE;
		if(task != null ){
			if(task.getMoveDocDetail() != null){
				MoveDoc moveDoc = commonDao.load(MoveDoc.class, task.getMoveDocDetail().getMoveDoc().getId());				
				billType =moveDoc.getBillType();
				moveDocCode = moveDoc.getCode();
			}else if(task.getPickTicketDetail()!=null){
				moveDocCode=task.getBhCode();
				logType=InventoryLogType.PICK_DOWN;
				if(moveDocCode==null||moveDocCode.equals("")){
					moveDocCode=task.getBillCode();
				}
			}
		}
		
		//库内移位
		moveToInventory(srcInventory, destLocation, null, quantity, null, task, worker, billType, moveDocCode);

		//更新托盘信息
//		if (srcInventory.getLP()!=null && srcInventory.getLP().getInventoryQty() == 0) {
//			removeLPRelations(srcInventory.getLP());
//		}
		//更新库位信息
		//task.getSrcLoc().refreshTotal();
		//destLocation.refreshTotal();
		Location srcLoc=srcInventory.getLocation();
		if(task!=null){
			srcLoc=task.getSrcLoc();
		}
		addInventoryLog(logType, -1, moveDocCode, 
				srcLoc, (srcInventory.getLP()==null?null:srcInventory.getLP().getLP()), 
				srcInventory.getItemKey(), srcInventory.getStorageDate(), 
				srcInventory.getSOI(), quantity, null, srcInventory.getStatus(), null, null, billType,srcInventory.getZone());
	}
	public void moveInvtlHc(List<Long> ids) {
		for(Long srcInvId:ids){
			Inventory inv=this.commonDao.get(Inventory.class, srcInvId);
			if( inv.getZzkw()!=null&& inv.getZzkw().getHckw()!=null){
				if(inv.getLocation().getId().equals(inv.getZzkw().getHckw().getId())){
					throw new BusinessException("投料库位不能相同");
				}
				moveInventory(srcInvId, inv.getZzkw().getHckw().getId(), inv.getAvaliableQuantity(), UserHolder.getUser().getName(), InventoryLogType.MOVE_HCKW, SysCode.HC_TL ,null, "暂存投料");
			}
		}
	}
	public void moveInvtlZz(List<Long> ids) {
		for(Long srcInvId:ids){
			Inventory inv=this.commonDao.get(Inventory.class, srcInvId);
			if( inv.getZzkw()!=null){
				if(inv.getLocation().getId().equals(inv.getZzkw().getId())){
					throw new BusinessException("投料库位不能相同");
				}
				moveInventory(srcInvId, inv.getZzkw().getId(), inv.getAvaliableQuantity(), UserHolder.getUser().getName(), InventoryLogType.MOVE_ZZKW, SysCode.ZZ_TL ,null, "制造投料");
			}
		}
	}
	public JSONObject moveInvtl(Long srcInvId,String locCode,double quantity, String oper,Long xpp_id,Long task_log_id,String locationType,String billCode) {
		PrintXppRecord xpp=this.commonDao.get(PrintXppRecord.class, xpp_id);
		PickTicketDetail ptd=xpp.getPtd();
		if(locationType.equals(LocationType.HCKW)&&(locCode==null||locCode.equals(""))){
			locCode= ptd.getZzkw().getHckwCode()==null?"": ptd.getZzkw().getHckwCode();
		}
		List<Location> locs=this.commonDao.findByQuery("from Location l where l.code='"+locCode+"' and l.type='"+locationType+"'");
		if(locs.size()<=0){
			throw new BusinessException("投料库位不存在");
		}
	
		
		//缓存库位投料，现品票在接收库位上
		String hql=" from Inventory i where i.barCode='XB' and i.zone.id="+ptd.getZone1().getId()
				+" and i.itemKey.id="+ptd.getItemKey().getId()+" and i.zzkw.id="+ptd.getZzkw().getId();
		String logType="";
		if(locationType.equals(LocationType.HCKW)){
			if(xpp.getHckw()!=null){
				throw new BusinessException("暂存库位已投料");
			}
			hql+=" and i.location.id="+ptd.getZone1().getHckw().getId();
			logType=InventoryLogType.MOVE_HCKW;
		}else if(locationType.equals(LocationType.PROCESS)){
			if(xpp.getZzkw()!=null){
				throw new BusinessException("制造库位已投料");
			}
			//如果已缓存投料，则在缓存库位上
			if(xpp.getHckw()!=null){
				hql+=" and i.location.id="+xpp.getHckw().getId();
			}else{
				hql+=" and i.location.id="+ptd.getZone1().getHckw().getId();
			}
			logType=InventoryLogType.MOVE_ZZKW;
		}
		List<Inventory> invs=this.commonDao.findByQuery(hql);
		if(invs.size()>0){
			Inventory inv=invs.get(0);
			if(inv.getQtyOfMasterPack()<xpp.getShsl()){
				throw new BusinessException("原库存数量不足");
			}
			this.moveInventory(inv.getId(), locs.get(0).getId(), quantity, oper, logType, SysCode.HC_TL, xpp.getXpp(), billCode);
		}else{
			throw new BusinessException("原库存不存在");
		}
		PickTicket pt=ptd.getPickTicket();
		double tls=xpp.getShsl();
		if(locationType.equals("HCKW")){
			xpp.setHckw(locs.get(0));
			xpp.setHcBy(oper);
			xpp.setHcDate(new Date());
			this.commonDao.store(xpp);
		}else if(locationType.equals("PROCESS")){
			if(xpp.getHcBy()!=null){
				tls=0;
			}
			xpp.setZzkw(locs.get(0));
			xpp.setZzBy(oper);
			xpp.setZzDate(new Date());
			this.commonDao.store(xpp);
		}
		pt.setTlBy(oper);
		pt.setTlQty(pt.getTlQty()+tls);
		pt.setTlDate(new Date());
		ptd.setTlQty(tls+ptd.getTlQty());
		if(pt.getTlQty()>0){
			pt.setStatus(PickTicketStatus.FEEDING);
			if(pt.getTlQty()==pt.getShippedQuantity()){
				pt.setStatus(PickTicketStatus.FEEDED);
			}
		}
		this.commonDao.store(pt);
		JSONObject obj= new JSONObject();
		obj.put("total_tl_qty",(int)pt.getShippedQuantity());
		obj.put("tl_qty",(int)pt.getTlQty());
		obj.put("dd_tl_qty",(int)pt.getShippedQuantity()-(int)pt.getTlQty());
		String status="已收货";
		if(pt.getStatus().equals(PickTicketStatus.CLOSE)){
			status="已收货";
		}if(pt.getStatus().equals(PickTicketStatus.FEEDING)){
			status="投料中";
		}if(pt.getStatus().equals(PickTicketStatus.FEEDED)){
			status="投料完成";
		}else{
			status=pt.getStatus();
		}
		obj.put("status", status);
		return obj;
	}
	
	
	public void moveInventory(Long srcInvId, Long destLocId,double quantity, String oper,String logType,String type,String xpp,String billCode) {
		if(destLocId == null){
			throw new BusinessException("destlocation.not.null");
		}
		Inventory srcInv = commonDao.load(Inventory.class, srcInvId);
		Location destLoc = commonDao.load(Location.class, destLocId);
		//记录源库存数量减少日志
		Inventory destInv=this.findInventory(srcInv.getItemKey(), srcInv.getZone(), destLoc, null,type,srcInv.getZzkw());
		double srcQty1=srcInv.getQtyOfMasterPack();
		srcInv.remove(quantity, 0, 0);
		this.commonDao.store(srcInv);
		double srcQty2=destInv.getQtyOfMasterPack();
		destInv.add(quantity, 0, 0);
		this.commonDao.store(destInv);
		//减少
		addInventoryLog(logType, -1, srcInv.getZone(), srcInv.getLocation(), billCode, srcInv.getItemKey(), quantity, xpp, oper, srcInv.getId(), (int)srcQty1+"变为"+(int)srcInv.getQtyOfMasterPack(), null, null, null, srcInv.getZzkw());
		//增加
		addInventoryLog(logType, 1, destInv.getZone(), destInv.getLocation(), billCode, destInv.getItemKey(), quantity, xpp, oper, destInv.getId(), (int)srcQty2+"变为"+(int)destInv.getQtyOfMasterPack(), null, null, null, destInv.getZzkw());
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#manualMove(java.lang.Long, java.lang.Long, java.lang.String, java.lang.Long, double)
	 */
	public void manualMove(Long srcInventoryId, Long destLocationId,double quantity, Long workerId,String reseaon) {
		Inventory srcInv = commonDao.load(Inventory.class, srcInventoryId);
		Location srcLoc = srcInv.getLocation();
		Location dstLoc = commonDao.load(Location.class, destLocationId);

		Stock dstStock = null;
		double quantityMU = quantity;
		if (quantityMU > srcInv.getAvaliableQuantity()) {
			throw new BusinessException("inventory.quantity.insufficient");
		}
		if(destLocationId == null){
			throw new BusinessException("destlocation.not.null");
		}
		Worker worker = (workerId == null ? null : commonDao.load(Worker.class, workerId));
		Inventory srcInventory = commonDao.load(Inventory.class, srcInventoryId);
		Location destLocation = commonDao.load(Location.class, destLocationId);
		//记录源库存数量减少日志
		BillType billType = null;
		String moveDocCode = null;
		String logType=InventoryLogType.MOVE;			
		//库内移位
		moveToInventory(srcInventory, destLocation, null, quantity, null, null, worker, billType, reseaon);
//		addInventoryLog(logType, -1, moveDocCode, 
//				srcLoc, (srcInventory.getLP()==null?null:srcInventory.getLP().getLP()), 
//				srcInventory.getItemKey(), srcInventory.getStorageDate(), 
//				srcInventory.getSOI(), quantity, null, srcInventory.getStatus(), null, reseaon, billType,srcInventory.getZone());
//		
		addInventoryLog(logType, -1, srcInventory.getZone(), srcLoc, "库内移位", srcInventory.getItemKey(),
				Math.abs(quantity), null, UserHolder.getUser().getName(), srcInventory.getId(),  srcInventory.getQtyOfMasterPack()+quantity+"库存调整"+srcInventory.getQtyOfMasterPack(),reseaon, null, null, srcInventory.getZzkw());
	}
	
	

	private Stock getStockWithNew(Location location, String lp, PackageUnit unit, double quantity) {
		Stock stock = null;
		if (!StringUtils.isEmpty(lp)) {
			stock = (Stock) commonDao.findByNamedQueryUniqueResult("getStockByCode", 
					new String[] {"warehouseId", "code"}, new Object[] {location.getWarehouse().getId(), lp});
			if (stock == null) {
				//创建托盘
				stock = EntityFactory.getEntity(Stock.class);
				stock.setWarehouse(location.getWarehouse());
				stock.setLocation(location);
				stock.setLP(lp);
				stock.setType(StockType.PALLET);
				stock.setItemQty(quantity*unit.getConvertFigure());
				stock.setWeight(quantity*unit.getWeight());
				stock.setVolume(quantity*unit.getVolume());
				stock.setLocationIndex(0);
				stock.setEnabled(true);
				stock.setInventoryQty(0);
				LPFormat lpFormat = unit.getFitLPFormat(location.getStowage().getHeight());
				stock.setStackHighQty(lpFormat==null?0:lpFormat.getStackHighQty());
				stock.setTierQty(lpFormat==null?0:lpFormat.getStackHighQty());
				commonDao.store(stock);
			}
		}
		return stock;
	}

	/* (non-Javadoc)
     * @see com.dev.swms.server.service.inventory.InventoryManager#splitPackageUnit(long, long, double)
     */
    public void convertPackageUnit(Long srcInventoryId, Long destPackageUnitId, double packQuantity) {
        Inventory srcInventory = commonDao.load(Inventory.class, srcInventoryId);
        PackageUnit destPackageUnit = commonDao.load(PackageUnit.class, destPackageUnitId);
        
    	//不允许转换超过库存可用数量库存
        double convertQtyMU = packQuantity * destPackageUnit.getConvertFigure();
        if (convertQtyMU > srcInventory.getAvaliableQuantity()) {
        	convertQtyMU = srcInventory.getAvaliableQuantity();
        }
    	double leftQty = srcInventory.getAvaliableQuantity() - convertQtyMU;
    	//包装转换时，托盘信息保持不变
    	Stock destLP = srcInventory.getLP();
    	
    	//修改原库存剩余数量
    	this.adjustInventoryUpdateWithNoLog(srcInventory, leftQty);
        //更新目标库存数量
        Inventory dstPackInventory = this.adjustInventoryAddWithNoLog(srcInventory.getLocation(), 
        		srcInventory.getItemKeyInventory().getItemKey(), convertQtyMU, destPackageUnit, 
        		destLP,	srcInventory.getStatus(), srcInventory.getStorageDate(), srcInventory.getSOI(), Boolean.FALSE,srcInventory.isBeLock(),srcInventory.isBeReject());
        
		addInventoryLog(InventoryLogType.CONVERT_PACKAGEUNIT, -1, null, 
				srcInventory.getLocation(), (srcInventory.getLP()==null?null:srcInventory.getLP().getLP()), 
				srcInventory.getItemKeyInventory().getItemKey(), srcInventory.getStorageDate(), 
				srcInventory.getSOI(), convertQtyMU, destPackageUnit, srcInventory.getStatus(), null, null, null,srcInventory.getZone());
		addInventoryLog(InventoryLogType.CONVERT_PACKAGEUNIT, 1, null, 
				dstPackInventory.getLocation(),	(dstPackInventory.getLP()==null?null:dstPackInventory.getLP().getLP()), 
				dstPackInventory.getItemKeyInventory().getItemKey(), dstPackInventory.getStorageDate(), 
				dstPackInventory.getSOI(), convertQtyMU, destPackageUnit, dstPackInventory.getStatus(), null, null, null,dstPackInventory.getZone());
    }

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#ship(java.lang.Long, com.dev.swms.server.model.base.ItemKey, double, java.lang.Long, java.util.Date, java.lang.String)
	 */
	public void ship(Long locationId, ItemKey itemKey, double quantity, Long packageUnitId, Long LP, 
			String status, Date storageDate, String soi, String relatedBill, BillType billType) {
		String barCode=null;
		double weight=0;
		double volume=0;
		Location location = commonDao.load(Location.class, locationId);
//		PackageUnit packageUnit = commonDao.load(PackageUnit.class, packageUnitId);
		Stock stock = (LP == null ? null : commonDao.load(Stock.class, LP));
		//对数量预先做格式化处理，统一小数位数
		quantity = DoubleUtils.formatByPrecision(quantity, 0);//packageUnit.getPrecision());
		if (quantity == 0) {
			return;
		}
		
		Inventory inventory = this.ship(itemKey, location, quantity, status);
		if(inventory==null){
			throw new BusinessException("未找到满足库存数据");
		}
//		if(inventory.getStatus().equals("不良品")){
//			throw new BusinessException("库存也锁定");
//		}
		//更新托盘信息
		if (stock!=null && stock.getInventoryQty() == 0) {
			removeLPRelations(stock);
		}
		//更新库位信息
		location.refreshTotal();
		int figure=1;//packageUnit.getConvertFigure()
		addInventoryLog(InventoryLogType.SHIPPING, -1, relatedBill, location, (stock==null?null:stock.getLP()), 
				inventory.getItemKey(), storageDate, soi, 
				quantity*figure, null, inventory.getStatus(), null, null, billType,inventory.getZone());
	}

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#countAdjust(java.util.List, java.lang.String)
	 */
	public void countAdjust(List<Long> inventoryIds, String description) {
		for (Long inventoryId : inventoryIds) {
			Inventory inventory = commonDao.load(Inventory.class, inventoryId);
			double oldQuantity = inventory.getQtyOfMasterPack();
			adjustInventoryUpdateWithNoLog(inventory, 0);
			
			//更新托盘信息
			if (inventory.getLP()!=null && inventory.getLP().getInventoryQty() == 0) {
				removeLPRelations(inventory.getLP());
			}
			//更新库位信息
			inventory.getLocation().refreshTotal();
			
			//库存调整日志记录
			int incOrDec = (oldQuantity > 0 ? -1 : 1);
			addInventoryLog(InventoryLogType.COUNT_ADJUST, incOrDec, null, 
					inventory.getLocation(), (inventory.getLP()==null?null:inventory.getLP().getLP()), 
					inventory.getItemKeyInventory().getItemKey(), inventory.getStorageDate(), inventory.getSOI(), 
					Math.abs(oldQuantity), inventory.getPackageUnit(), inventory.getStatus(), null, description, null,inventory.getZone());
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#lockInventory(java.util.List, java.lang.String, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public void lockInventory(List<Long> inventoryIds,String lockType,String status){
		Set set = new HashSet();
		for (Long id : inventoryIds) {
			Inventory inventory = commonDao.load(Inventory.class, id);
			//根据锁定类型，将被选中记录的相应条件保存进集合
			if(!inventory.isLocked()){
				set = storeConditionToSet(set,inventory,lockType);
				//如果是库存锁，则单独锁定
				if(InventoryLockType.INVENTORY.equals(lockType)
						&& (LocationType.STORAGE.equals(inventory.getLocation().getType()) || LocationType.TRANSIT.equals(inventory.getLocation().getType())))
					setInventoryQuantity(inventory, status);
			}
		}
		//查找满足集合里条件的所有库存记录，并锁定
		operateSet(set,status,lockType,"lock");
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#unlockInventory(java.util.List, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public void unlockInventory(List<Long> inventoryIds,String lockType) {
		
		Set set = new HashSet();
		for (Long id : inventoryIds) {
			Inventory inventory = commonDao.load(Inventory.class, id);
			//根据锁定类型，将被选中记录的相应条件保存进集合
			if(inventory.isLocked()){
				set = storeConditionToSet(set,inventory,lockType);
				//如果是库存锁，则单独锁定
				if(InventoryLockType.INVENTORY.equals(lockType) 
						&& (LocationType.STORAGE.equals(inventory.getLocation().getType()) || LocationType.TRANSIT.equals(inventory.getLocation().getType())))
					setInventoryQuantity(inventory, "");
			}
		}
		//查找满足集合里条件的所有库存记录，并解锁
		operateSet(set, "", lockType, "unlock");
	}
	public void lockInventory(List<Long> inventoryIds){
		for(Long id:inventoryIds){
			Inventory inventory = commonDao.load(Inventory.class, id);
			if(inventory.isLocked()){
//				inventory.setStatus("不良品");
				setInventoryQuantity(inventory, "不良品");
				commonDao.store(inventory);
			}
		}
	}
	public void unlockInventory(List<Long> inventoryIds){
		for(Long id:inventoryIds){
			Inventory inventory = commonDao.load(Inventory.class, id);
			if(!inventory.isLocked()){
//				inventory.setStatus("");
				setInventoryQuantity(inventory, "");
				commonDao.store(inventory);
				
			}
		}
		
	}
	
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#inventoryQuality(com.dev.swms.server.model.inventory.Inventory, double)
	 */
	@SuppressWarnings("unchecked")
	public void inventoryQuality(Inventory inventory, double quantity, Long packageUnitId) {
		double weight=0;
		double volume=0;
		String barCode=null;
		Inventory srcInv = commonDao.load(Inventory.class, inventory.getId());
		PackageUnit unit = commonDao.load(PackageUnit.class, packageUnitId);
		//如果质检登记数量大于库存可用数量则终止操作
		if (DoubleUtils.compareByPrecision(quantity * unit.getConvertFigure(), 
				srcInv.getAvaliableQuantity(), srcInv.getPackageUnit().getPrecision())>0) {
			//if (quantity * unit.getConvertFigure() > srcInv.getAvaliableQuantity()) {
			throw new BusinessException("quality.quantity.error");
		}
		//获取已定义库位列表(如果存在)
		List<Location> destLocs4Quality = commonDao.findByNamedQuery("getLocationsByType", 
				new String[]{"type", "warehouseId"}, 
				new Object[]{LocationType.QUALITY, srcInv.getLocation().getWarehouse().getId()}); 
		//判断是否定义质检库位
		if (destLocs4Quality == null || destLocs4Quality.isEmpty()) {
			throw new BusinessException("quality.location.none");
		}
		//库存移位
		ItemKeyInventory itemKeyInventory = srcInv.getItemKeyInventory();
		Inventory destInv = itemKeyInventory.getInventoryWithNew(destLocs4Quality.get(0), 
				unit, null, barCode,Inventory.STATUS_QUALITY, srcInv.getStorageDate(), srcInv.getSOI(),srcInv.isBeLock(),srcInv.isBeReject());
		destInv.add(quantity * unit.getConvertFigure(),weight,volume);
		InventoryLog log1 = new InventoryLog(InventoryLogType.MOVE, 1, null, null, 
				destInv.getLocation(), (destInv.getLP()==null?null:destInv.getLP().getLP()), 
				destInv.getItemKeyInventory().getItemKey(),	destInv.getStorageDate(), destInv.getSOI(), 
				quantity * unit.getConvertFigure(), unit, destInv.getStatus(), null, Inventory.STATUS_QUALITY,destInv.getZone());
		commonDao.store(log1);
		
		//如果全部库存都被移走, 则删除原库存, 避免0库存的产生
		itemKeyInventory.removeInventory(srcInv, quantity * unit.getConvertFigure(),weight,volume);
		InventoryLog log2 = new InventoryLog(InventoryLogType.MOVE, -1, null, null,	srcInv.getLocation(), 
				(srcInv.getLP()==null?null:srcInv.getLP().getLP()),	srcInv.getItemKeyInventory().getItemKey(), 
				srcInv.getStorageDate(), srcInv.getSOI(), quantity * unit.getConvertFigure(), unit, 
				srcInv.getStatus(), log1.getId(), Inventory.STATUS_QUALITY,srcInv.getZone());
		commonDao.store(log2);

		//更新托盘信息
		if (srcInv.getLP() != null && srcInv.getLP().getInventoryQty()==0) {
			removeLPRelations(srcInv.getLP());
		}
		//更新源库位信息
		srcInv.getLocation().refreshTotal();
		
		//获取源库存对应收货单的收货记录上的之间数量
		ASN dbASN = (ASN)commonDao.findByNamedQueryUniqueResult("getASNByCodeAndWarehouse", 
				new String[]{"code", "warehouseId"}, 
				new Object[]{srcInv.getSOI(), srcInv.getLocation().getWarehouse().getId()});
		if (dbASN != null) {
			double qualityQty = quantity * unit.getConvertFigure();
			for (ReceivedRecord rr : dbASN.getReceivedRecords()) {
				if (StringUtils.isEmpty(rr.getMoveDocCode()) 
						&& rr.getItemKey().getId().equals(srcInv.getItemKeyInventory().getItemKey().getId())
						&& rr.getPackageUnit().getId().equals(srcInv.getPackageUnit().getId())) {
					if (DoubleUtils.compareByPrecision(rr.getReceivedQuantity()*rr.getPackageUnit().getConvertFigure(), 
							qualityQty, rr.getPackageUnit().getPrecision())>=0) {
						//if (rr.getReceivedQuantity()*rr.getPackageUnit().getConvertFigure() >= qualityQty) {
						rr.quality(qualityQty);
						break;
					} else {
						rr.quality(rr.getReceivedQuantity()*rr.getPackageUnit().getConvertFigure());
						qualityQty -= rr.getReceivedQuantity()*rr.getPackageUnit().getConvertFigure();
					}
				}
				commonDao.store(rr);
				if (qualityQty <= 0) {
					break;
				}
			}
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#qualityPass(java.util.List)
	 */
	@SuppressWarnings("unchecked")
	public void qualityPass(List<Long> inventoryIds) {
		//汇总所有需要处理的库存
		Set<Inventory> areadlyAddInvs = new HashSet<Inventory>();
		for (Long id : inventoryIds) {
			Inventory inventory = commonDao.load(Inventory.class, id);
			//如果该库存已经处理过则跳过该库存继续下一个库存
			if (!areadlyAddInvs.contains(inventory)) {
				List<Inventory> inventories = commonDao.findByNamedQuery("getInventoriesQuality", 
						new String[]{"warehouseId", "itemKeyId"}, 
						new Object[]{inventory.getLocation().getWarehouse().getId(),
								inventory.getItemKeyInventory().getItemKey().getId()});
				for (Inventory itemInv : inventories) {
					//检查质检库位上是否有已质检通过或质检失败但未完成上架库存（避免重复创建上架计划）
					if (!itemInv.getId().equals(inventory.getId()) 
							&& itemInv.getLocation().getType().equals(LocationType.QUALITY)
							&& itemInv.getStatus().equals(Inventory.STATUS_VALID)) {
						throw new BusinessException("quality.item.duplicate");
					}
				}
				areadlyAddInvs.addAll(inventories);
			}
		}
		String barCode=null;
		double weight=0;
		double volume=0;
		//修改库存状态
		for (Inventory inventory : areadlyAddInvs) {
			double qty = inventory.getAvaliableQuantity();
			ItemKeyInventory itemKeyInventory = inventory.getItemKeyInventory();
			Inventory destInv = itemKeyInventory.getInventoryWithNew(inventory.getLocation(), 
					inventory.getPackageUnit(), inventory.getLP(), barCode, Inventory.STATUS_VALID, 
					inventory.getStorageDate(), inventory.getSOI(),inventory.isBeLock(),inventory.isBeReject());
			destInv.add(qty, weight, volume);
			itemKeyInventory.removeInventory(inventory, qty,weight, volume);
		}
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#qualityFail(java.util.List)
	 */
	@SuppressWarnings("unchecked")
	public void qualityFail(List<Long> inventoryIds) {
		//汇总所有需要处理的库存
		Set<Inventory> areadlyAddInvs = new HashSet<Inventory>();
		for (Long id : inventoryIds) {
			Inventory inventory = commonDao.load(Inventory.class, id);
			//如果该库存已经处理过则跳过该库存继续下一个库存
			if (!areadlyAddInvs.contains(inventory)) {
				List<Inventory> inventories = commonDao.findByNamedQuery("getInventoriesQuality", 
						new String[]{"warehouseId", "itemKeyId"}, 
						new Object[]{inventory.getLocation().getWarehouse().getId(),
								inventory.getItemKeyInventory().getItemKey().getId()});
				for (Inventory itemInv : inventories) {
					//检查质检库位上是否有已质检通过或质检失败但未完成上架库存（避免重复上架）
					if (!itemInv.getId().equals(inventory.getId()) 
							&& itemInv.getLocation().getType().equals(LocationType.QUALITY)
							&& itemInv.getStatus().equals(Inventory.STATUS_VALID)) {
						throw new BusinessException("quality.item.duplicate");
					}
				}
				
				areadlyAddInvs.addAll(inventories);
			}
		}
		String barCode=null;
		double weight=0;
		double volume=0;
		//修改库存状态
		for (Inventory inventory : areadlyAddInvs) {
			double qty = inventory.getAvaliableQuantity();
			ItemKeyInventory itemKeyInventory = inventory.getItemKeyInventory();
			Inventory destInv = itemKeyInventory.getInventoryWithNew(inventory.getLocation(), 
					inventory.getPackageUnit(), inventory.getLP(),barCode, Inventory.STATUS_FAILED, 
					inventory.getStorageDate(), inventory.getSOI(),inventory.isBeLock(),inventory.isBeReject());
			destInv.add(qty, weight, volume);
			itemKeyInventory.removeInventory(inventory, qty, weight, volume);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#qualityScrap(com.dev.swms.server.model.inventory.Inventory, double)
	 */
	@SuppressWarnings("unchecked")
	public void qualityScrap(Inventory inventory, double quantity, Long packageUnitId) {
		String barCode=null;
		double weight=0;
		double volume=0;
		Inventory srcInv = commonDao.load(Inventory.class, inventory.getId());
		PackageUnit unit = commonDao.load(PackageUnit.class, packageUnitId);
		//如果质检报废数量大于库存数量则终止操作
		if (DoubleUtils.compareByPrecision(quantity * unit.getConvertFigure(), 
				srcInv.getAvaliableQuantity(), srcInv.getPackageUnit().getPrecision())>=0) {
			//if (quantity * unit.getConvertFigure() > srcInv.getAvaliableQuantity()) {
			throw new BusinessException("scrap.quantity.error");
		}
		//获取已定义报废库位列表(如果存在)
		List<Location> destLocs4Quality = commonDao.findByNamedQuery("getLocationsByType", 
				new String[]{"type", "warehouseId"}, 
				new Object[]{LocationType.BAD, srcInv.getLocation().getWarehouse().getId()}); 
		//判断是否定义报废库位
		if (destLocs4Quality == null || destLocs4Quality.isEmpty()) {
			throw new BusinessException("quality.locationBad.none");
		}
		//库存移位
		ItemKeyInventory itemKeyInventory = srcInv.getItemKeyInventory();
		Inventory destInv = itemKeyInventory.getInventoryWithNew(destLocs4Quality.get(0), 
				unit, null, barCode,Inventory.STATUS_BAD, srcInv.getStorageDate(), srcInv.getSOI(),srcInv.isBeLock(),srcInv.isBeReject());
		destInv.add(quantity*unit.getConvertFigure(),weight,volume);
		InventoryLog log1 = new InventoryLog(InventoryLogType.MOVE, 1, destInv.getSOI(), null,
				destInv.getLocation(), destInv.getLP()==null?null:destInv.getLP().getLP(), 
				destInv.getItemKeyInventory().getItemKey(),	destInv.getStorageDate(), destInv.getSOI(), 
				quantity*unit.getConvertFigure(), unit,	destInv.getStatus(), null, null,destInv.getZone());
		commonDao.store(log1);
		//如果全部库存都被移走, 则删除原库存, 避免0库存的产生
		itemKeyInventory.removeInventory(srcInv, quantity*unit.getConvertFigure(),weight,volume);
		InventoryLog log2 = new InventoryLog(InventoryLogType.MOVE, -1, srcInv.getSOI(), null,
				srcInv.getLocation(), srcInv.getLP()==null?null:srcInv.getLP().getLP(), 
				srcInv.getItemKeyInventory().getItemKey(), srcInv.getStorageDate(), srcInv.getSOI(), 
				quantity*unit.getConvertFigure(), unit,	srcInv.getStatus(), log1.getId(), null,srcInv.getZone());
		commonDao.store(log2);
	
		//更新托盘信息
		if (srcInv.getLP() !=null && srcInv.getLP().getInventoryQty()==0) {
			removeLPRelations(srcInv.getLP());
		}
		//更新库位信息
		srcInv.getLocation().refreshTotal();
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#processDown(java.lang.Long, double)
	 */
	public void processDown(Long srcInventoryId, double quantity, ProcessDoc processDoc) {
		Inventory srcInventory = commonDao.load(Inventory.class, srcInventoryId);
		ItemKeyInventory itemKeyInventory = srcInventory.getItemKeyInventory();
		//对数量预先做格式化处理，统一小数位数
		quantity = DoubleUtils.formatByPrecision(quantity, srcInventory.getPackageUnit().getPrecision());
		double weight=0;
		double volume=0;
		//删除库存数据
		itemKeyInventory.removeInventory(srcInventory, 
				quantity*srcInventory.getPackageUnit().getConvertFigure(),weight,volume);
		
		//更新托盘信息
		if (srcInventory.getLP()!=null && srcInventory.getLP().getInventoryQty()==0) {
			removeLPRelations(srcInventory.getLP());
		}
		//更新库位信息
		srcInventory.getLocation().refreshTotal();
		
		//库存日志记录
		addInventoryLog(InventoryLogType.PROCESS_DOWN, -1, processDoc.getCode(), srcInventory.getLocation(), 
				srcInventory.getLP()==null?null:srcInventory.getLP().getLP(), 
				srcInventory.getItemKeyInventory().getItemKey(), 
				srcInventory.getStorageDate(), processDoc.getCode(), 
				quantity*srcInventory.getPackageUnit().getConvertFigure(), srcInventory.getPackageUnit(),
				srcInventory.getStatus(), null, null, processDoc.getBillType(),srcInventory.getZone());
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#processUp(java.lang.Long, com.dev.swms.server.model.base.ItemKey, double, java.lang.Long, java.lang.Long, java.lang.String, java.lang.String, java.util.Date, java.lang.String)
	 */
	public void processUp(Long locationId, ItemKey itemKey, double quantity, Long packageUnitId, 
			Long LP, String qualityCode, Date receiveDate, ProcessDoc processDoc,Boolean lock,Boolean reject) {
		Location location = commonDao.load(Location.class, locationId);
		PackageUnit packageUnit = commonDao.load(PackageUnit.class,packageUnitId);
		Stock stock = (LP == null ? null : commonDao.load(Stock.class, LP));
		//对数量预先做格式化处理，统一小数位数
		quantity = DoubleUtils.formatByPrecision(quantity, packageUnit.getPrecision());
		if (quantity == 0) {
			return;
		}
		String barCode=null;
		double weight=0;
		double volume=0;
		WarehouseArea zone=null;
		//收货到库存
		Inventory inventory = receiveToInventory(location, itemKey, quantity, packageUnit, zone, barCode, weight, volume,
				processDoc.getCode(), qualityCode, receiveDate,lock,reject);
		
		//更新库位信息
		location.refreshTotal();
		
		//写库存日志
		addInventoryLog(InventoryLogType.PROCESS_UP, 1, processDoc.getCode(), location, 
				(stock==null?null:stock.getLP()), inventory.getItemKeyInventory().getItemKey(), receiveDate, 
				processDoc.getCode(), quantity*packageUnit.getConvertFigure(), packageUnit, 
				inventory.getStatus(), null, null, processDoc.getBillType(),inventory.getZone());
	}
	
	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#storeInventoryItemKey(com.dev.swms.server.model.inventory.Inventory, java.lang.String)
	 */
	@SuppressWarnings("unchecked")
	public void storeInventoryItemKey(Inventory inventory, String type,Double quantity,Double invQuantity,Long keyID,String propC1,Date propD1,Date propD2,Date storageDate) {
		ItemKey itemKey = commonDao.load(ItemKey.class, keyID);
		itemKey.getLotInfo().setPropD1(propD1);
		itemKey.getLotInfo().setPropD2(propD2);
//		ItemKey itemKeyNew = new ItemKey();
//		itemKeyNew.setContent(propC1);
//		itemKeyNew.setItem(itemKey.getItem());
//		itemKeyNew.setSOI(itemKey.getSOI());
//		itemKeyNew.setLot(codeManager.getCodeForYm("",5));//codeManager.generateLot());
//		itemKeyNew.setStorageDate(itemKey.getStorageDate());
//		LotInfo l=new LotInfo();
//		l.setPropC1(propC1);
//		l.setPropD1(propD1);
//		l.setPropD2(propD2);
//		itemKeyNew.setLotInfo(l);
		inventory = this.load(Inventory.class, inventory.getId());
		//如果输入批次属性与原批次属性相同，则不做调整
//		ItemKey dbItemKey = itemManager.getItemKey(itemKeyNew, Boolean.TRUE);
//		if (dbItemKey.equals(inventory.getItemKeyInventory().getItemKey())&&inventory.getStorageDate().equals(storageDate)) {
//			throw new BusinessException("itemKey.update.duplicate");
//		}
		
		//如果不允许批次混放，每次批次调整时必须库位上所有库存全部批次调整
//		Location loc = commonDao.load(Location.class, inventory.getLocation().getId());
//		if (!loc.isMixLot() && type.equals(EditLotInfoType.BYINVENTORY)) {
//			throw new BusinessException("itemKey.modify.byInventory.invalid");
//		} else if (loc.isMixLot() && type.equals(EditLotInfoType.BYLOCATION)) {
//			throw new BusinessException("itemKey.modify.byLocation.invalid");
//		}
		//找到属于同一批次的库存(无锁、未分配、存货库位)
//		List<Inventory> list = new ArrayList<Inventory>();
//		if (EditLotInfoType.BYLOT.equals(type)) {
//			list.addAll(commonDao.findByNamedQuery("getValidInventoriesByItemKey",
//					new String[]{"itemKeyId","warehouseId"},
//					new Object[]{itemKey.getId(), inventory.getItemKeyInventory().getWarehouse().getId()}));
//		} else if (EditLotInfoType.BYLOCATION.equals(type)) {
//			list.addAll(loc.getInventories());
//			loc.setCurrentItem(dbItemKey.getItem().getId());
//			loc.setCurrentLot(dbItemKey.getId());
//		} else {
//			list.add(commonDao.load(Inventory.class, inventory.getId()));
//		}
		
		//批次调整时如果库存上有queue数量，则queue的数量对应批次不做调整（避免移位错误）
//		for(Inventory iv : list){
//			//增加新批次库存
//			double newQty =quantity;
//			double oldQty = invQuantity-quantity;
//			adjustInventoryAddWithNoLog(iv.getLocation(), dbItemKey, newQty, iv.getPackageUnit(), 
//					iv.getLP(), iv.getStatus(), storageDate, iv.getSOI(), Boolean.FALSE,iv.isBeLock(),iv.isBeReject());
//			InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_LOT, 1, null, iv.getLocation(), 
//					(iv.getLP()==null?null:iv.getLP().getLP()),	dbItemKey, iv.getStorageDate(), iv.getSOI(), 
//					newQty,	iv.getPackageUnit(), iv.getStatus(), null, null, null);
//			//扣减原批次库存
//			adjustInventoryUpdateWithNoLog(iv, oldQty);
//			addInventoryLog(InventoryLogType.MODIFY_LOT, -1, null, iv.getLocation(), 
//					iv.getLP()==null?null:iv.getLP().getLP(), iv.getItemKeyInventory().getItemKey(), iv.getStorageDate(), 
//					iv.getSOI(), newQty, iv.getPackageUnit(), iv.getStatus(), log1.getId(), null, null);
//		}
		LocalizedMessage.addMessage("itemKey.already.modify", new String[] {itemKey.getLot()});
	}

	public void addInventory(Long itemKeyId,Inventory inventory, String lp,String description) {
		Location loc = commonDao.load(Location.class, inventory.getLocation().getId());
		ItemKey itemKey = load(ItemKey.class,itemKeyId);
		LotInfo lotInfo = itemKey.getLotInfo();
		Item item = commonDao.load(Item.class, itemKey.getItem().getId());
		ItemKey dbKey = itemManager.getItemKey(new ItemKey(
				"", item, lotInfo, inventory.getStorageDate(), inventory.getSOI(),itemKey.getPinfan()), Boolean.TRUE,null);
		PackageUnit unit = commonDao.load(PackageUnit.class, inventory.getPackageUnit().getId());
		
		Stock stock = getStockWithNew(loc, lp, unit, inventory.getQuantity());
		
		adjustInventoryAdd(loc, dbKey, inventory.getQuantity()*unit.getConvertFigure(), unit, 
				stock, Inventory.STATUS_VALID, inventory.getStorageDate(), inventory.getSOI(), 
				InventoryLogType.INVENTORY_ADJUST, description, null, null,inventory.isBeLock(),inventory.isBeReject());
	}
	
	public void importInv(File file){
		Workbook workbook;
		try {
			workbook = Workbook.getWorkbook(file);
			Sheet sheet = workbook.getSheet(0);//得到excel第一页的内容
			SimpleDateFormat yy = new SimpleDateFormat("yyyyMMdd");
			for (int i = 1; i <sheet.getRows(); i++) {
				System.out.println(i);
//			for (int i = 226; i <228; i++) {
				 //货主名称	物料编码	库位	库存数量    重量	批号	生产日期	破损	货位类型
			 	String cus_code=sheet.getCell(0,i).getContents().trim();
			 	String zone_code=sheet.getCell(1,i).getContents().trim();
			 	if(cus_code==null||cus_code.equals("")){
			 		return;
			 	}
				Structure s=null;
				List<Structure> ss=this.commonDao.findByQuery("from Structure s where s.name=:code",new String[]{"code"},new Object[]{cus_code});
				if(ss.size()>0){
		    			s=ss.get(0);
				}else{
		    			throw new BusinessException("代码为"+cus_code+"的货主不存在");
		    		}
				WarehouseArea zone=null;
				
				List<WarehouseArea> zones=this.commonDao.findByQuery("from WarehouseArea s where s.name=:code",new String[]{"code"},new Object[]{zone_code});
				if(zones.size()>0){
					zone=zones.get(0);
				}else{
		    			throw new BusinessException("代码为"+cus_code+"的货主不存在");
		    		}
				String item_code=sheet.getCell(2,i).getContents().trim();
				String AC=sheet.getCell(3,i).getContents().trim();
				String jg=sheet.getCell(4,i).getContents().trim();
				String sb=sheet.getCell(5,i).getContents().trim();
				String quantity=sheet.getCell(6,i).getContents().trim();
				String loc_code=sheet.getCell(7,i).getContents().trim();

				List<Location> locs=this.commonDao.findByQuery("from Location l where l.code='"+loc_code+"'");
				if(locs.size()>0){ 
					Location l=locs.get(0);
					List<Item> items=this.commonDao.findByQuery("from Item i where i.code='"+item_code+"' and i.company.id="+s.getId());
					if(items.size()>0){
						Item item=items.get(0);
						List<Pinfan> pflist=commonDao.findByQuery(" from Pinfan p where p.item.id="+item.getId()+" and p.specs='"+AC+"' "
								+ " AND p.content='"+jg+"' AND p.bonded='"+sb+"' ");
						if(pflist.size()>0) {
								Pinfan pinfan=pflist.get(0);
						LotInfo lotInfo=new LotInfo();
//						lotInfo.setPropC1(propC1);
//						lotInfo.setPropD1(DateUtil.formatStrToDateYMD(d1));
						ItemKey dbKey = itemManager.getItemKey(new ItemKey(
								"", item, lotInfo, new Date(), "",pinfan), Boolean.TRUE,null);
						PackageUnit unit =item.getMinPackageUnit();
						Inventory inventory = this.adjustInventoryAdd(dbKey,zone,l, 
								Double.parseDouble(quantity),"",true,true);
						inventory.setBarCode("XB");
						this.commonDao.store(inventory);
//						inventory.setWeight(Double.parseDouble(whitd));
						commonDao.store(inventory);
						InventoryLog log2 = new InventoryLog(InventoryLogType.INVENTORY_ADJUST, 1, "初始化库存", null, inventory.getItemKey().getPinfan().getLocation(), null, inventory.getItemKey(), 
								new Date(), "初始化库存", Double.parseDouble(quantity), null, null, inventory.getId(), inventory.getStatus(),inventory.getZone());
						commonDao.store(log2);
						}
					}else{
						throw new BusinessException("第"+(i+1)+"行货品代码"+item_code+"不存在");
					}
				}else{
					throw new BusinessException("第"+(i+1)+"行库位代码"+loc_code+"不存在");
				}
			 }
		} catch (BiffException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	

	

	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#compute(java.util.Date)
	 */
	@SuppressWarnings("unchecked")
	public void compute(Date date,Long warehouseId) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar = DateUtils.truncate(calendar, Calendar.DATE);
		Date currentDate = calendar.getTime();
		int curYear = calendar.get(Calendar.YEAR);
		int curMonth = calendar.get(Calendar.MONTH)+1;
		calendar.add(Calendar.DATE, -1);
		Date beforeOneDayDate = calendar.getTime();
		calendar.add(Calendar.DATE, 2);
		Date afterOneDayDate = calendar.getTime();
		logger.info("Start calculate StorageDaily for: " + currentDate);
		
		//计算当日进出汇总数据
		//1、先删除原来计算的storageDaily
		//2、拷贝前一天storageDaily作为当天的初始数据
		//2、对每一个itemKeyInventory计算当日的发生数量
		//3、对每一个itemKeyInventory逐一检查是否有前日的storageDaily存在，如有则提取结存数量为当日期初数量
		//4、将计算结果写入storageDaily
		long startTimeMillis = System.currentTimeMillis();
		logger.debug("Delete exists storageDaily!"); 
		commonDao.executeByNamed("deleteStorageDailyByDate", new String[] {"computeDate","warehouseId"}, 
				new Object[] {currentDate,warehouseId});
		logger.debug("Delete exists storageDaily finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		
		startTimeMillis = System.currentTimeMillis();
		logger.debug("Duplicate previous storageDaily!");
		List<StorageDaily> preDailys = commonDao.findByNamedQuery("getStorageDailyByDate", 
				new String[] {"computeDate","warehouseId"}, 
				new Object[] {beforeOneDayDate,warehouseId});
		List<StorageDaily> curDailys = new ArrayList<StorageDaily>(); 
		for (StorageDaily preDaily : preDailys) {
			StorageDaily curDaily = EntityFactory.getEntity(StorageDaily.class);
			curDaily.setComputeDate(currentDate);
			curDaily.setComputeYear(curYear);
			curDaily.setComputeMonth(curMonth);
			curDaily.setWarehouse(preDaily.getWarehouse());
			curDaily.setItemKey(preDaily.getItemKey());
			curDaily.setPreviousQuantity(preDaily.getLeftQuantity());
			curDaily.setLeftQuantity(preDaily.getLeftQuantity());
			commonDao.store(curDaily);
			curDailys.add(curDaily);
		}
		preDailys = null;
		logger.debug("Duplicate previous storageDaily finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		
		startTimeMillis = System.currentTimeMillis();
		logger.debug("Compute inventoryLog!");
		List<InventoryLog> logs = commonDao.findByNamedQuery("getInventoryLogByDate", 
				new String[] {"startTime","endTime","warehouseId"}, 
				new Object[] {currentDate, afterOneDayDate,warehouseId});
		for (InventoryLog log : logs) {
			StorageDaily tempDaily =  EntityFactory.getEntity(StorageDaily.class);
			tempDaily.setComputeDate(currentDate);
			tempDaily.setItemKey(log.getItemKey());
			tempDaily.setWarehouse(log.getWarehouse());
			//由于库存日志发生数量为包装数量，进销存日志中无包装单位，因此结转时需折算为基本单位数量进行处理
			double quantity = log.getOccurQuantity()*log.getIncOrDec();
			if (log.getLogType().equals(InventoryLogType.RECEIVING)) {
				tempDaily.setInQuantity(quantity);
			} else if (log.getLogType().equals(InventoryLogType.SHIPPING)) {
				tempDaily.setOutQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.PROCESS_DOWN)){
				tempDaily.setProcessDownQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.PROCESS_UP)){
				tempDaily.setProcessUpQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.COUNT_ADJUST)){
				tempDaily.setCountAdjustQuantity(quantity);
			}else if(log.getLogType().equals(InventoryLogType.COMPANY_TRANS_IN)){
				tempDaily.setCompanyTransInQuantity(quantity);
			}else if(log.getLogType().equals(InventoryLogType.COMPANY_TRANS_OUT)){
				tempDaily.setCompanyTransOutQuantity(quantity);
			}
			StorageDaily daily = null;
			if (curDailys.contains(tempDaily)) {
				daily = curDailys.get(curDailys.indexOf(tempDaily));
				daily.setInQuantity(daily.getInQuantity()+tempDaily.getInQuantity());
				daily.setOutQuantity(daily.getOutQuantity()+tempDaily.getOutQuantity());
				daily.setProcessDownQuantity(daily.getProcessDownQuantity()+tempDaily.getProcessDownQuantity());
				daily.setProcessUpQuantity(daily.getProcessUpQuantity()+tempDaily.getProcessUpQuantity());
				daily.setCountAdjustQuantity(daily.getCountAdjustQuantity()+tempDaily.getCountAdjustQuantity());
				daily.setLeftQuantity(daily.getInQuantity()+daily.getOutQuantity()+daily.getCountAdjustQuantity()+daily.getProcessDownQuantity()+daily.getProcessUpQuantity()+daily.getCompanyTransInQuantity()+daily.getCompanyTransOutQuantity());
				daily.setCompanyTransInQuantity(daily.getCompanyTransInQuantity()+tempDaily.getCompanyTransInQuantity());
				daily.setCompanyTransOutQuantity(daily.getCompanyTransOutQuantity()+tempDaily.getCompanyTransOutQuantity());
			} else {
				daily =  EntityFactory.getEntity(StorageDaily.class);
				daily.setWarehouse(log.getWarehouse());
				daily.setItemKey(log.getItemKey());
				daily.setComputeDate(currentDate);
				daily.setComputeYear(curYear);
				daily.setComputeMonth(curMonth);
				Double leftQuantity = (Double) commonDao.findByNamedQueryUniqueResult("getLeftQuantityByItemKeyInvAndDate", 
						new String[] {"warehouseId","itemKeyId","computeDate"}, 
						new Object[] {log.getWarehouse().getId(), log.getItemKey().getId(), currentDate});
				if (leftQuantity != null) {
					tempDaily.setPreviousQuantity(leftQuantity);
				}
				daily.setInQuantity(daily.getInQuantity()+tempDaily.getInQuantity());
				daily.setOutQuantity(daily.getOutQuantity()+tempDaily.getOutQuantity());
				daily.setProcessDownQuantity(daily.getProcessDownQuantity()+tempDaily.getProcessDownQuantity());
				daily.setProcessUpQuantity(daily.getProcessUpQuantity()+tempDaily.getProcessUpQuantity());
				daily.setCountAdjustQuantity(daily.getCountAdjustQuantity()+tempDaily.getCountAdjustQuantity());
				daily.setLeftQuantity(daily.getInQuantity()+daily.getOutQuantity()+daily.getCountAdjustQuantity()+daily.getProcessDownQuantity()+daily.getProcessUpQuantity()+daily.getCompanyTransInQuantity()+daily.getCompanyTransOutQuantity());
				daily.setCompanyTransInQuantity(daily.getCompanyTransInQuantity()+tempDaily.getCompanyTransInQuantity());
				daily.setCompanyTransOutQuantity(daily.getCompanyTransOutQuantity()+tempDaily.getCompanyTransOutQuantity());
				curDailys.add(daily);
			}
			commonDao.store(daily);
			log.setComputeDate(currentDate);
			commonDao.store(log);
		}
		logger.debug("Compute inventoryLog finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		logs = null;
		logger.info("finished calculate StorageDaily for: " + currentDate);
	}

	/*自动计算StorageDaily
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#compute()
	 */
	public void compute() {
		Calendar calendar = Calendar.getInstance();
		calendar.add(Calendar.DATE, -1);
//		List<Long> wavehouseIds = this.commonDao.findByQuery("select id from Warehouse where disabled = false");
//		for(Long warehouseId:wavehouseIds){
//			try {
//				compute(calendar.getTime(),warehouseId);
//				Thread.sleep(1000);
//			} catch (Exception e) {
//				e.printStackTrace();
//			}
//		}
		
//		compute(calendar.getTime());
		SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
		SwmsSequenceDao computeDao = (SwmsSequenceDao)ac.getBean("swmsSequenceDao");
		computeDao.computeStorageDailyByProcedure(df.format(calendar.getTime()));
	}
	
	private void compute(Date date){
		Calendar calendar = Calendar.getInstance();
		calendar.setTime(date);
		calendar = DateUtils.truncate(calendar, Calendar.DATE);
		Date currentDate = calendar.getTime();
		int curYear = calendar.get(Calendar.YEAR);
		int curMonth = calendar.get(Calendar.MONTH)+1;
		calendar.add(Calendar.DATE, -1);
		Date beforeOneDayDate = calendar.getTime();
		calendar.add(Calendar.DATE, 2);
		Date afterOneDayDate = calendar.getTime();
		logger.info("Start calculate StorageDaily for: " + currentDate);
		
		//计算当日进出汇总数据
		//1、先删除原来计算的storageDaily
		//2、拷贝前一天storageDaily作为当天的初始数据
		//2、对每一个itemKeyInventory计算当日的发生数量
		//3、对每一个itemKeyInventory逐一检查是否有前日的storageDaily存在，如有则提取结存数量为当日期初数量
		//4、将计算结果写入storageDaily
		long startTimeMillis = System.currentTimeMillis();
		logger.debug("Delete exists storageDaily!"); 
		commonDao.executeByNamed("deleteAllStorageDailyByDate", new String[] {"computeDate"}, 
				new Object[] {currentDate});
		logger.debug("Delete exists storageDaily finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		
		this.commonDao.load(StorageDaily.class,0L);//刷新session，迫使hibernate提交删除的数据
		
		startTimeMillis = System.currentTimeMillis();
		logger.debug("Duplicate previous storageDaily!");
		List<StorageDaily> preDailys = commonDao.findByNamedQuery("getAllStorageDailyByDate", 
				new String[] {"computeDate"}, 
				new Object[] {beforeOneDayDate});
		
		List<StorageDaily> curDailys = new ArrayList<StorageDaily>(); 
		for (StorageDaily preDaily : preDailys) {
			StorageDaily curDaily = EntityFactory.getEntity(StorageDaily.class);
			curDaily.setComputeDate(currentDate);
			curDaily.setComputeYear(curYear);
			curDaily.setComputeMonth(curMonth);
			curDaily.setWarehouse(this.commonDao.load(Warehouse.class,preDaily.getWarehouse().getId()));
			curDaily.setItemKey(this.commonDao.load(ItemKey.class,preDaily.getItemKey().getId()));
			curDaily.setPreviousQuantity(preDaily.getLeftQuantity());
			curDaily.setLeftQuantity(preDaily.getLeftQuantity());
			commonDao.store(curDaily);
			curDailys.add(curDaily);
		}
		preDailys = null;
		logger.debug("Duplicate previous storageDaily finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		
		startTimeMillis = System.currentTimeMillis();
		logger.debug("Compute inventoryLog!");
		
		List<InventoryLog> logs = commonDao.findByNamedQuery("getTempInventoryLogByDate", 
				new String[] {"startTime","endTime"}, 
				new Object[] {currentDate, afterOneDayDate});
		for(InventoryLog log:logs){
			StorageDaily tempDaily =  EntityFactory.getEntity(StorageDaily.class);
			tempDaily.setComputeDate(currentDate);
			tempDaily.setItemKey(this.commonDao.load(ItemKey.class,log.getItemKey().getId()));
			tempDaily.setWarehouse(this.commonDao.load(Warehouse.class,log.getWarehouse().getId()));
			//由于库存日志发生数量为包装数量，进销存日志中无包装单位，因此结转时需折算为基本单位数量进行处理
			double quantity = log.getOccurQuantity()*log.getIncOrDec();
			if (log.getLogType().equals(InventoryLogType.RECEIVING)) {
				tempDaily.setInQuantity(quantity);
			} else if (log.getLogType().equals(InventoryLogType.SHIPPING)) {
				tempDaily.setOutQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.PROCESS_DOWN)){
				tempDaily.setProcessDownQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.PROCESS_UP)){
				tempDaily.setProcessUpQuantity(quantity);
			} else if(log.getLogType().equals(InventoryLogType.COUNT_ADJUST)){
				tempDaily.setCountAdjustQuantity(quantity);
			}else if(log.getLogType().equals(InventoryLogType.COMPANY_TRANS_IN)){
				tempDaily.setCompanyTransInQuantity(quantity);
			}else if(log.getLogType().equals(InventoryLogType.COMPANY_TRANS_OUT)){
				tempDaily.setCompanyTransOutQuantity(quantity);
			}

			StorageDaily daily = containsDaily(curDailys,tempDaily);
			if (daily!=null) {
				daily.setInQuantity(daily.getInQuantity()+tempDaily.getInQuantity());
				daily.setOutQuantity(daily.getOutQuantity()+tempDaily.getOutQuantity());
				daily.setProcessDownQuantity(daily.getProcessDownQuantity()+tempDaily.getProcessDownQuantity());
				daily.setProcessUpQuantity(daily.getProcessUpQuantity()+tempDaily.getProcessUpQuantity());
				daily.setCountAdjustQuantity(daily.getCountAdjustQuantity()+tempDaily.getCountAdjustQuantity());
				daily.setCompanyTransInQuantity(daily.getCompanyTransInQuantity()+tempDaily.getCompanyTransInQuantity());
				daily.setCompanyTransOutQuantity(daily.getCompanyTransOutQuantity()+tempDaily.getCompanyTransOutQuantity());
				daily.setLeftQuantity(daily.getPreviousQuantity()+daily.getInQuantity()+daily.getOutQuantity()+daily.getCountAdjustQuantity()+daily.getProcessDownQuantity()+daily.getProcessUpQuantity()+daily.getCompanyTransInQuantity()+daily.getCompanyTransOutQuantity());
			} else {
				daily =  EntityFactory.getEntity(StorageDaily.class);
				daily.setWarehouse(log.getWarehouse());
				daily.setItemKey(this.commonDao.load(ItemKey.class,log.getItemKey().getId()));
				daily.setComputeDate(currentDate);
				daily.setComputeYear(curYear);
				daily.setComputeMonth(curMonth);
				Double leftQuantity = (Double) commonDao.findByNamedQueryUniqueResult("getLeftQuantityByItemKeyInvAndDate", 
						new String[] {"warehouseId","itemKeyId","computeDate"}, 
						new Object[] {log.getWarehouse().getId(), log.getItemKey().getId(), currentDate});
				if (leftQuantity != null) {
					tempDaily.setPreviousQuantity(leftQuantity);
				}
				daily.setInQuantity(daily.getInQuantity()+tempDaily.getInQuantity());
				daily.setOutQuantity(daily.getOutQuantity()+tempDaily.getOutQuantity());
				daily.setProcessDownQuantity(daily.getProcessDownQuantity()+tempDaily.getProcessDownQuantity());
				daily.setProcessUpQuantity(daily.getProcessUpQuantity()+tempDaily.getProcessUpQuantity());
				daily.setCountAdjustQuantity(daily.getCountAdjustQuantity()+tempDaily.getCountAdjustQuantity());
				daily.setCompanyTransInQuantity(daily.getCompanyTransInQuantity()+tempDaily.getCompanyTransInQuantity());
				daily.setCompanyTransOutQuantity(daily.getCompanyTransOutQuantity()+tempDaily.getCompanyTransOutQuantity());
				daily.setLeftQuantity(daily.getPreviousQuantity()+daily.getInQuantity()+daily.getOutQuantity()+daily.getCountAdjustQuantity()+daily.getProcessDownQuantity()+daily.getProcessUpQuantity()+daily.getCompanyTransInQuantity()+daily.getCompanyTransOutQuantity());
				curDailys.add(daily);
			}
			commonDao.store(daily);
			log.setComputeDate(currentDate);
			commonDao.store(log);
		}
		logger.debug("Compute inventoryLog finished, spend Time: " + (System.currentTimeMillis() - startTimeMillis));
		logs = null;
		logger.info("finished calculate StorageDaily for: " + currentDate);
	}
	
	private StorageDaily containsDaily(List<StorageDaily> curDailys, StorageDaily daily){
		for(StorageDaily dl:curDailys){
			if(dl.getWarehouse().getId().equals(daily.getWarehouse().getId()) 
					&& dl.getItemKey().getId().equals(daily.getItemKey().getId()) 
					&& dl.getComputeDate()==daily.getComputeDate()){
				return dl;
			}
		}
		return null;
	}
	
	/*
	 *  (non-Javadoc)
	 * @see com.dev.swms.server.service.inventory.InventoryManager#reCompute(java.util.Date)
	 */
	public void reCompute(Date startDate,Warehouse warehouse) {
		Calendar nowCalendar = DateUtils.truncate(Calendar.getInstance(), Calendar.DATE);
		nowCalendar.add(Calendar.DATE, 1);
		Calendar calendar = Calendar.getInstance();
		for(calendar.setTime(startDate);calendar.before(nowCalendar);calendar.add(Calendar.DATE, 1)){
			compute(calendar.getTime(),warehouse.getId());
		}
	}
	
	/**
	 * 根据锁定类型，将被选中记录的相应条件保存进集合
	 * */
	@SuppressWarnings("unchecked")
	private Set storeConditionToSet(Set set,Inventory inventory,String lockType){
		//库位锁：锁定和选中记录库位相同的所有记录
		if(InventoryLockType.LOCATION.equals(lockType))
			//找出所有被选中记录的库位，并保存进集合
			set.add(inventory.getLocation());
		//货主锁
		else if(InventoryLockType.COMPANY.equals(lockType))
			set.add(inventory.getItemKeyInventory().getItemKey().getItem().getCompany());
		//批次锁
		else if(InventoryLockType.LOT.equals(lockType))
			set.add(inventory.getItemKeyInventory().getItemKey());
		//货品锁
		else if(InventoryLockType.ITEM.equals(lockType))
			set.add(inventory.getItemKeyInventory().getItemKey().getItem());
		
		return set;
	}
	
	/**
	 * 对保存查询条件集合的操作,查找满足集合里条件的所有库存记录，并锁定
	 * yufei.ge
	 * */
	@SuppressWarnings("unchecked")
	private void operateSet(Set set,String status,String lockType,String type){
		for(Object o:set){
			//库位锁
			if(InventoryLockType.LOCATION.equals(lockType)){
				Location location = (Location)o;
				String sql = "from Inventory inv where (inv.location.type = 'STORAGE' or inv.location.type = 'TRANSIT') and inv.location.id = " + location.getId();
				setInventoryStatus(status, sql, type);
			}
			//货主锁
			else if(InventoryLockType.COMPANY.equals(lockType)){
				Structure organization = (Structure)o;
				String sql = "from Inventory inv where (inv.location.type = 'STORAGE' or inv.location.type = 'TRANSIT')  and inv.itemKeyInventory.itemKey.item.company.id = " + organization.getId();
				setInventoryStatus(status,sql,type); 
			}
			//批次锁
			else if(InventoryLockType.LOT.equals(lockType)){
				ItemKey itemKey = (ItemKey)o;
				String sql = "from Inventory inv where (inv.location.type = 'STORAGE' or inv.location.type = 'TRANSIT') and inv.itemKeyInventory.itemKey.id = " + itemKey.getId();
				setInventoryStatus(status,sql,type);
			}
			//货品锁
			else if(InventoryLockType.ITEM.equals(lockType)){
				Item item = (Item)o;
				String sql = "from Inventory inv where (inv.location.type = 'STORAGE' or inv.location.type = 'TRANSIT') and inv.itemKeyInventory.itemKey.item.id = " + item.getId();
				setInventoryStatus(status,sql,type);
			}
		}
	}
	
	/**
	 * 设置库存状态
	 * yufei.ge
	 * */
	@SuppressWarnings("unchecked")
	private void setInventoryStatus(String status,String sql,String type){
		if ("lock".equals(type)) {
			//状态必须为未锁定且库存数量可以操作的记录才能锁定
			sql += " and  inv.status is null and inv.quantity>0 and inv.queuedQuantity=0";
		} else {
			////状态必须为锁定记录才能解除锁定
			sql += " and (inv.status is not null) ";
		}
		List invs = this.commonDao.findByQuery(sql);
		for(Object o:invs){
			Inventory inventory = (Inventory)o;
			if("lock".equals(type)){
				//如果待锁定的选项没有被锁定,则锁定
				setInventoryQuantity(inventory,status);
			} else if (!StringUtils.isEmpty(inventory.getStatus())) {
				//否则解锁
				setInventoryQuantity(inventory, "");
			}
		}
	}
	
	/**
	 * 设置库存数量
	 * yufei.ge
	 * */
	private void setInventoryQuantity(Inventory inventory,String status){
		double qty = inventory.getAvaliableQuantity();
		String barCode=null;
		double weight=0;
		double volume=0;
		//创建新库存
		Inventory inv1 = inventory.getItemKeyInventory().adjustInventoryAdd(inventory.getLocation(),
				qty, inventory.getPackageUnit(), inventory.getLP(), barCode, weight, volume,status, 
				inventory.getStorageDate(), inventory.getSOI(),inventory.isBeLock(),inventory.isBeReject());
		InventoryLog log1 = new InventoryLog(InventoryLogType.INVENTORY_ADJUST, 1, inv1.getSOI(), null,
				inv1.getLocation(), inv1.getLP()==null?null:inv1.getLP().getLP(), 
				inv1.getItemKeyInventory().getItemKey(), inv1.getStorageDate(), inv1.getSOI(), qty, 
				inventory.getPackageUnit(), inv1.getStatus(), null, null,inv1.getZone());
		commonDao.store(log1);
		
		//扣减原有库存数量
		Inventory inv2 = inventory.getItemKeyInventory().adjustInventoryRemove(inventory.getLocation(),
				qty, inventory.getPackageUnit(),inventory.getLP(),barCode, weight, volume,inventory.getStatus(),
				inventory.getStorageDate(),inventory.getSOI());
		InventoryLog log2 = new InventoryLog(InventoryLogType.INVENTORY_ADJUST, -1, inv2.getSOI(), null,
				inv2.getLocation(), inv2.getLP()==null?null:inv2.getLP().getLP(), 
				inv2.getItemKeyInventory().getItemKey(), inv2.getStorageDate(), inv2.getSOI(), qty, 
				inventory.getPackageUnit(), inv2.getStatus(), log1.getId(), null,inv2.getZone());
		commonDao.store(log2);
	}

	@SuppressWarnings("unchecked")
	public List<ProductInventory> getProductInventories(List<String> items, String warehouse) {
		//TODO: 大数据量时，sql语句拼接方式存在64K长度限制问题
		String hql = "SELECT new com.dev.swms.server.model.inventory.ProductInventory(pinv.warehouse,pinv.customer,pinv.product,pinv.lot,SUM(pinv.quantity) AS quantity) " + 
			"FROM ProductInventory pinv WHERE pinv.warehouse = '" + warehouse +"' ";
		//查询货品数量大于1000时，只取前1000个进行查询
		if (items.size() > 1000) {
			items = items.subList(0, 999);
		} 
		hql += " AND (";
		int i = 1;
		for (String item : items) {
			hql += "pinv.unicode like '" + item + "%' ";
			if (i < items.size()) {
				hql += " OR ";
			}
			i ++;
		}
		hql += ")";
		hql += " GROUP BY pinv.warehouse,pinv.customer,pinv.product,pinv.lot";
		hql += " ORDER BY pinv.warehouse,pinv.customer,pinv.product,pinv.lot";
		return commonDao.findByQuery(hql);
	}
	
	/**
	 * 新增库存(不创建日志)
	 * @param locationId 目标库位ID
	 * @param itemKey 批次属性
	 * @param quantity 新增数量（基本单位数量）
	 * @param packageUnitId 包装单位
	 * @param LP 托盘
	 * @param status 库存状态
	 * @param storageDate 存货日期
	 * @param soi SOI
	 * @return
	 */
	private Inventory adjustInventoryAddWithNoLog(Location location, ItemKey itemKey, double quantity, 
		PackageUnit packageUnit, Stock LP, String status, Date storageDate, String soi, boolean countAdjust,Boolean lock,Boolean reject) {
		String barCode=null;
		double weight=0;
		double volume=0;
		//锁检查
		if (location.bePutAwayLock() && !countAdjust) {
			throw new BusinessException("location.locked");
		}
		//托盘检查
		if (LP != null && location.getStowage().getLpLimit()<=0) {
			throw new BusinessException("location.stock.unavaliable");
		}
		//混放检查(存货库位)
		if (LocationType.STORAGE.equals(location.getType())) {
			if (!location.beMixAble(itemKey.getItem().getId(), itemKey.getId())) {
				throw new BusinessException("location.mixCheck.invalid");
			}
		}

		ItemKeyInventory itemKeyInventory = getItemKeyInventory(location.getWarehouse(), itemKey);
		//对数量预先做格式化处理，统一小数位数
		quantity = DoubleUtils.formatByPrecision(quantity, packageUnit.getPrecision());
		
		Inventory inventory = itemKeyInventory.adjustInventoryAdd(location, 
				quantity, packageUnit, LP, barCode, weight, volume,status, storageDate, soi,lock,reject);
		storeItemKeyInventory(itemKeyInventory);
		return inventory;
	}

	/**
	 * 修改库存（不创建日志）
	 * @param inventory 待修改库存
	 * @param quantity 修改后数量（基本单位数量）
	 */
	private void adjustInventoryUpdateWithNoLog(Inventory inventory, double quantity) {
		//对数量预先做格式化处理，统一小数位数
		quantity = DoubleUtils.formatByPrecision(quantity, inventory.getPackageUnit().getPrecision());

		ItemKeyInventory itemKeyInventory = inventory.getItemKeyInventory();
		if (DoubleUtils.compareByPrecision(quantity, 
				inventory.getQueuedQuantity(), inventory.getPackageUnit().getPrecision())<0) {
			//if (quantity < inventory.getQueuedQuantity()) {
			//只能对库内的可用库存（总库存－已分配库存）进行调整
			throw new BusinessException("inventory.quantity.insufficient");
		} 
		
		itemKeyInventory.adjustInventoryUpdate(inventory, quantity);
		storeItemKeyInventory(itemKeyInventory);
	}
    
	/**
	 * 库内移位共用方法
	 * @param srcInventory 源库存
	 * @param destLocation 目标库位
	 * @param dstLP 目标托盘
	 * @param quantity 移位数量（基本单位数量）
	 * @return
	 */
	private void moveToInventory(Inventory srcInventory, Location destLocation, Stock dstLP, double quantity, 
			PackageUnit packageUnit, Task task, Worker worker, BillType billType, String relatedBill){
		String barCode=null;
		double weight=task==null?0:task.getWeight();
		double volume=0;
		WarehouseArea zone=srcInventory.getZone();
		if(task!=null){
			zone=task.getZone();
		}
		//库位入锁检查
//		if (destLocation.bePutAwayLock()) {
//			throw new BusinessException("location.locked");
//		}
		//不能同库位内移位
//		if (srcInventory.getLocation().equals(destLocation)) {
//			throw new BusinessException("inventory.move.sameLocation");
//		}
		//混放检查(存货库位)
//		if (LocationType.STORAGE.equals(destLocation.getType())) {
//			if (!destLocation.beMixAble(srcInventory.getItemKey().getItem().getId(), 
//					srcInventory.getItemKey().getId())) {
//				throw new BusinessException("location.mixCheck.invalid");
//			}
//		}
//		//移动到备货、发货或加工库位后，去除托盘信息
//		if(LocationType.READY.equals(destLocation.getType())
//				|| LocationType.SHIP.equals(destLocation.getType())
//				|| LocationType.PROCESS.equals(destLocation.getType())) {
//			dstLP = null;
//		}
//		if (dstLP != null && destLocation.getStowage().getLpLimit()<=0) {
//			throw new BusinessException("location.lpStore.avaliable");
//		}
//		//托盘校验---非整托移位时不允许目标库位与原库位托盘相同
//		if (srcInventory.getLP()!=null && srcInventory.getLP().getInventoryQty() > quantity) {
//			if (srcInventory.getLP().getId().equals(dstLP)) {
//				throw new BusinessException("LP.fullMove.destLocation.sameLP");
//			}
//		}
		//目标库位是备货或加工库位时，直接拆为基本包装移位
		//如果目标库位有定义拆箱级别，根据目标库位的拆箱级别进行包装转换
		//否则以指定的包装单位进行包装转换
		Item item = srcInventory.getItemKey().getItem();
//		if (LocationType.READY.equals(destLocation.getType())
//				|| LocationType.PROCESS.equals(destLocation.getType())) {
//			packageUnit = srcInventory.getMasterPackUnit();
//		} else if (destLocation.getMuPick() > 0) {
//			packageUnit = item.getPackageUnitByLineNo(destLocation.getMuPick());
//		}

		ItemKey itemKey = srcInventory.getItemKey();
		itemKey.removeInventory(srcInventory, quantity,weight,volume);
		Inventory destInventory=null;
		
		//货物移动到发货库位时，要进行整包装分解处理
		Double packQty = quantity;//Math.floor(quantity/packageUnit.getConvertFigure());
		Double leftQtyMU = DoubleUtils.formatByPrecision(quantity - packQty,
				1);
		if (LocationType.SHIP.equals(destLocation.getType()) || destLocation.getMuPick() == 0) {
			//登记剩余零散数量
			if (leftQtyMU > 0) {
				Inventory destMUInventory =getInventoryNew(itemKey,srcInventory.getZone(),destLocation, srcInventory.getStatus());
				destMUInventory.add(leftQtyMU,weight,volume);
				this.commonDao.store(destMUInventory);
				itemKey.getInventories().add(destMUInventory);
				if (task != null) {
					task.pickConfirm(itemKey, task.getSrcLoc(), 
							srcInventory.getLP(), destLocation, dstLP, srcInventory.getStatus(),
							srcInventory.getStorageDate(), srcInventory.getSOI(), 
							destMUInventory.getPackageUnit(), leftQtyMU, worker);
				}
			}
			//登记包装数量
			if (packQty > 0) {
				destInventory = getInventoryNew(itemKey,zone,destLocation, srcInventory.getStatus());
				destInventory.setZzkw(srcInventory.getZzkw());
				destInventory.add(packQty,weight,volume);
				this.commonDao.store(destInventory);
				itemKey.getInventories().add(destInventory);
				if (task != null) {
					task.pickConfirm(itemKey, task.getSrcLoc(), 
							srcInventory.getLP(), destLocation, dstLP, srcInventory.getStatus(),
							srcInventory.getStorageDate(), srcInventory.getSOI(), 
							destInventory.getPackageUnit(), packQty, worker);
				}
			}
		} else {
			destInventory = getInventoryNew(itemKey,srcInventory.getZone(),destLocation, srcInventory.getStatus());
			destInventory.add(quantity,weight,volume);
			this.commonDao.store(destInventory);
			itemKey.getInventories().add(destInventory);
			if (task != null) {
				if (leftQtyMU > 0) {
					task.pickConfirm(itemKey, task.getSrcLoc(), 
						srcInventory.getLP(), destLocation, dstLP, srcInventory.getStatus(),
						srcInventory.getStorageDate(), srcInventory.getSOI(), 
						srcInventory.getMasterPackUnit(), leftQtyMU, worker);
				}
				if (packQty > 0) {
					task.pickConfirm(itemKey, task.getSrcLoc(), 
						srcInventory.getLP(), destLocation, dstLP, srcInventory.getStatus(),
						srcInventory.getStorageDate(), srcInventory.getSOI(), 
						destInventory.getPackageUnit(), packQty, worker);
				}
			}
			
		}
		commonDao.store(itemKey);
		String logType=InventoryLogType.MOVE;
		String des=null;
		if(task!=null){
			if(task.getPickTicketDetail()!=null){
				relatedBill=task.getCode();
				logType=InventoryLogType.PICK_DOWN;
			}
			//对目标库存记录库存日志
			addInventoryLog(logType, 1, relatedBill, destLocation, 
					(dstLP==null?null:dstLP.getLP()), itemKey, srcInventory.getStorageDate(), 
					srcInventory.getSOI(), quantity, packageUnit, srcInventory.getStatus(), null, des, billType,srcInventory.getZone());
		}else{
			des=relatedBill;
			addInventoryLog(logType, 1, srcInventory.getZone(), destLocation, "库内移位", srcInventory.getItemKey(),
					Math.abs(quantity), null, UserHolder.getUser().getName(), destLocation.getId(),  destInventory.getQtyOfMasterPack()-quantity+"库存调整"+destInventory.getQtyOfMasterPack(),des, null, null, srcInventory.getZzkw());

		}
		
	}

	/**
	 * 库存记录货主转换
	 * inventoryId:源库存记录
	 * companyBId：目标货主
	 */
	public void companyTrans(Long inventoryId, Long companyBId, double transQuantity,String moveType) {
		Inventory inventory = this.commonDao.load(Inventory.class,inventoryId);
		String barCode=null;
		double weight=0;
		double volume=0;
		double leftQty = 0;
		if(moveType.equals("Move_Inv")){
			leftQty=inventory.getAvaliableQuantity()-transQuantity;
		}else if(moveType.equals("Move_Trans")){
			inventory.setQueuedQuantity(inventory.getQueuedQuantity()-transQuantity);
			this.commonDao.store(inventory);
			leftQty=inventory.getAvaliableQuantity()-transQuantity;
		}
		if(leftQty < 0){
			throw new BusinessException("companyTrans.transQuantity.erro");
		}
		Structure companyB = this.commonDao.load(Structure.class,companyBId);
		//带供应商属性的不允许做货主转移
		if(inventory.getItemKeyInventory().getItemKey().getLotInfo().getPropL1()!=null 
				|| inventory.getItemKeyInventory().getItemKey().getLotInfo().getPropL2()!=null 
				|| inventory.getItemKeyInventory().getItemKey().getLotInfo().getPropL3()!=null){
			throw new BusinessException("canTrans.inv.propL.erro");
		}
		Item itemA=inventory.getItemKeyInventory().getItemKey().getItem();
		Item itemB = canTrans(itemA,companyB);
		if(itemB==null){
			throw new BusinessException("canTrans.companyB.item.erro",new String[]{companyB.getName()});
		}
		//转入货主的库存（新增ItemKey、新增库存记录、增加“货权转出”库存日志）
		ItemKey itemKeyB = itemManager.getItemKeyForCompanyTrans(inventory.getItemKeyInventory().getItemKey(),
				inventory.getItemKeyInventory().getItemKey().getStorageDate(),
				inventory.getItemKeyInventory().getItemKey().getSOI(),
				itemB);
		ItemKeyInventory iki1 = this.getItemKeyInventory(inventory.getLocation().getWarehouse(), itemKeyB);
		Inventory inv1 = iki1.adjustInventoryAdd(inventory.getLocation(), transQuantity, 
				itemKeyB.getItem().getMinPackageUnit(), inventory.getLP(),barCode, weight, volume, inventory.getStatus(), 
				inventory.getStorageDate(), inventory.getSOI(),inventory.isBeLock(),inventory.isBeReject());
		addInventoryLog(InventoryLogType.COMPANY_TRANS_IN, 1, null, inv1.getLocation(), 
				(inv1.getLP()==null?null:inv1.getLP().getLP()), iki1.getItemKey(), 
				inv1.getStorageDate(), inv1.getSOI(), transQuantity, inv1.getPackageUnit(), 
				inv1.getStatus(), null, Inventory.COMPANY_TRANS_IN, null,inv1.getZone());
		
		//转出货主的库存（删除库存记录、增加“货权转出”库存日志）
		ItemKeyInventory iki2 = inventory.getItemKeyInventory();
		leftQty=inventory.getQtyOfMasterPack()-transQuantity;
		iki2.adjustInventoryUpdate(inventory, leftQty);
		addInventoryLog(InventoryLogType.COMPANY_TRANS_OUT, -1, null, inventory.getLocation(), 
				(inventory.getLP()==null?null:inventory.getLP().getLP()), iki2.getItemKey(), 
				inventory.getStorageDate(), inventory.getSOI(), transQuantity, inventory.getPackageUnit(), 
				inventory.getStatus(), null, Inventory.COMPANY_TRANS_OUT, null,inventory.getZone());
	}
	
	private Item canTrans(Item itemA,Structure companyB){
		String hql = "select rule FROM CompanyTransRule rule WHERE rule.warehouse.id= "+ WarehouseHolder.getWarehouse().getId()+
			    " and rule.companyA.id="+itemA.getCompany().getId()+" and rule.companyB.id="+companyB.getId();
		CompanyTransRule rule = (CompanyTransRule)this.commonDao.findByQueryUniqueResult(hql,
				new String[]{},	new Object[]{});
		if(rule==null){
			throw new BusinessException("canTrans.rules.null");
		}
		if(rule.isCanTrans()){
			//如果允许代码直转， 如果没找到对照表里的信息，就看这个代码在目标货主的货品清单中是否存在， 如果有就转，如果还没有就不转
			for(CompanyTransRuleDetail detail:rule.getDetails()){
				if(detail.getItemCode1().equals(itemA.getCode())){
					hql = "select item FROM Item item  WHERE item.code = '"+detail.getItemCode2()+
				     "' AND item.company.id = "+companyB.getId();
					Item itemB = (Item)this.commonDao.findByQueryUniqueResult(hql,
							new String[]{},	new Object[]{});
					if(itemB!=null)
						return itemB;
					break;
				}
			}
			hql = "select item FROM Item item  WHERE item.code = '"+itemA.getCode()+
			     "' AND item.company.id = "+companyB.getId();
			Item itemB = (Item)this.commonDao.findByQueryUniqueResult(hql,
					new String[]{},	new Object[]{});
			if(itemB!=null){
				return itemB;
			}else{
				itemB = EntityFactory.getEntity(Item.class);
				itemB.setCompany(companyB);
				itemB.setCode(itemA.getCode());
				itemB.setName(itemA.getName());
				itemB.setAlertLeadingDays(itemA.getAlertLeadingDays());
				itemB.setBrand(itemA.getBrand());
				itemB.setCAcoefficient(itemA.getCAcoefficient());
				itemB.setCAname(itemA.getCAname());
				itemB.setCenterClass(itemA.getCenterClass());
				itemB.setGoodType(itemA.getGoodType());
				itemB.setLocation(itemA.getLocation());
				itemB.setStorageType(itemA.getStorageType());
				itemB.setSpecs(itemA.getSpecs());
				itemB.setLength(itemA.getLength());
				itemB.setWidth(itemA.getWidth());
				itemB.setHeight(itemA.getHeight());
				itemB.setVolume(itemA.getVolume());
				itemB.setWeight(itemA.getWeight());
				itemB.setRoughWeight(itemA.getRoughWeight());
				itemB.setUnit(itemA.getUnit());
				this.commonDao.store(itemB);
				PackageUnit unitB = EntityFactory.getEntity(PackageUnit.class);
				PackageUnit pa=itemA.getMinPackageUnit();
				unitB.setUnit(pa.getUnit());
				unitB.setLineNO(pa.getLineNO());
				unitB.setConvertFigure(1);
				unitB.setItem(itemB);
				this.commonDao.store(unitB);
				itemB.addPackageUnit(unitB);
				this.commonDao.store(itemB);
				return itemB;
				//throw new BusinessException("canTrans.companyB.item.erro",new String[]{companyB.getName()});
			}
		}else{//如果不允许代码直转，就只能查规则明细表，查不到就不转
			for(CompanyTransRuleDetail detail:rule.getDetails()){
				if(detail.getItemCode1().equals(itemA.getCode())){
					hql = "select item FROM Item item  WHERE item.code = '"+detail.getItemCode2()+
				     "' AND item.company.id = "+companyB.getId();
					Item itemB = (Item)this.commonDao.findByQueryUniqueResult(hql,
							new String[]{},	new Object[]{});
					if(itemB!=null){
						return itemB;
					//break;
					}else{
						itemB = EntityFactory.getEntity(Item.class);
						itemB.setCompany(companyB);
						itemB.setCode(detail.getItemCode2());
						itemB.setName(itemA.getName());
						itemB.setAlertLeadingDays(itemA.getAlertLeadingDays());
						itemB.setBrand(itemA.getBrand());
						itemB.setCAcoefficient(itemA.getCAcoefficient());
						itemB.setCAname(itemA.getCAname());
						itemB.setCenterClass(itemA.getCenterClass());
						itemB.setGoodType(itemA.getGoodType());
						itemB.setLocation(itemA.getLocation());
						itemB.setStorageType(itemA.getStorageType());
						itemB.setSpecs(itemA.getSpecs());
						itemB.setLength(itemA.getLength());
						itemB.setWidth(itemA.getWidth());
						itemB.setHeight(itemA.getHeight());
						itemB.setVolume(itemA.getVolume());
						itemB.setWeight(itemA.getWeight());
						itemB.setRoughWeight(itemA.getRoughWeight());
						itemB.setUnit(itemA.getUnit());
						this.commonDao.store(itemB);
						PackageUnit unitB = EntityFactory.getEntity(PackageUnit.class);
						PackageUnit pa=itemA.getMinPackageUnit();
						unitB.setUnit(pa.getUnit());
						unitB.setLineNO(pa.getLineNO());
						unitB.setConvertFigure(1);
						unitB.setItem(itemB);
						this.commonDao.store(unitB);
						itemB.addPackageUnit(unitB);
						this.commonDao.store(itemB);
						return itemB;
					}
				}
			}
		}
		return null;
	}

	public String getMinPackageUnitByPageMap(Map map) {
		Long inventoryId = (Long)map.get("inventory.id");
		Inventory inventory = this.commonDao.load(Inventory.class,inventoryId);
		return inventory.getItemKeyInventory().getItemKey().getItem().getMinPackageUnit().getUnit();
	}
	
	public String getQuantityByPageMap(Map map) {
		Long inventoryId = (Long)map.get("inventory.id");
		Inventory inventory = this.commonDao.load(Inventory.class,inventoryId);
		return inventory.getQuantity()*inventory.getPackageUnit().getConvertFigure()+"";
	}
	
	
	/**增加自动创建大量库存功能
	 * 1. 按顺序提取库位定位分类对应的库位，并按照道排层列排序 
	 * 2. 要求产品大类和库位定位分类相同，这样可以找到能在这片区域方的货品 
	 * 3. 随机选取货品， 随机决定其放置1个还是2个库位。 对于其中的一个库位随机决定其存量 
	 * 4. 如果库位是托盘库位，随机决定是否放； 如果放的话，随机挑选可以放的商品整托存放 
	 * 5. 最后效果是仓库内80% 库位有东西。（但不一定是全满的） 
	 */
	public void autoCreateInventory() {
		List<Position> positions = this.commonDao.loadAll(Position.class);
		for(Position position:positions){
			String hql = "select item from Item item where item.largeClass='"+position.getName()+"'";
			List<Item> items = this.commonDao.findByQuery(hql);
			if(items.size()==0)
				continue;
			for(PositionDetail detail:position.getDetails()){
				List<Location> locs = getLocationsByPosition(detail);
				for(Location loc : locs){
					autoCreateInventorys(loc, items);
					//((HibernateDaoSupport)this.commonDao).getSessionFactory().getCurrentSession().flush();
				}
			}
		}
	}
	
	private List<Location> getLocationsByPosition(PositionDetail detail) {
		detail = this.commonDao.load(PositionDetail.class,detail.getId());
		String hql = "from Location location " +  
		" where location.disabled = false " +
		" and location.type = 'STORAGE' " +
		" and location.zone.id = " + detail.getZone().getId() +
		" and location.aisle >= " + detail.getStartAisle() +
		" and location.aisle <= " + detail.getEndAisle() + 
		" and location.line >= " + detail.getStartLine() +
		" and location.line <= " + detail.getEndLine() +
		" and ((location.row >= " + detail.getStartRow() + " and location.row <= " + detail.getEndRow() + ") " +
		" or (" + detail.getStartRow() + " = 0 and " + detail.getEndRow() + " = 0)) " +
		" and ((location.col >= " + detail.getStartCol() + " and location.col <= " + detail.getEndCol() + ") " +
		" or (" + detail.getStartCol() + " = 0 and " + detail.getEndCol() + " = 0)) " + 
		" order by location.aisle,location.line,location.row,location.col";
		
		List<Location> locs = commonDao.findByQuery(hql);
		
		return locs;
	}
	
	/**
	 * 按照大类和库位创建库存
	 * @param largeClass
	 * @param loc
	 */
	private void autoCreateInventorys(Location loc, List<Item> items){
		Random random = new Random();
		String barCode=null;
		double weight=0;
		double volume=0;
		//如果库位是托盘库位，随机决定是否放； 如果放的话，随机挑选可以放的商品整托存放
		if(loc.getStowage().getLpLimit()>0){
			if((random.nextInt()%2)==0){//如果是托盘库位，而且要放货品(随机)
				for(Item it:items){
					if(it.getDefaultLotRule()!=null){
						if(it.getLPPackageUnit()!=null){
							Stock stock = autoCreateInvForLP(loc,it);
							if(stock!=null){
								ItemKey itemKey = getItemKey(it);
								this.receiving(loc.getId(),itemKey,stock.getItemQty(),it.getLPPackageUnit().getId(),
										stock.getId(),barCode, weight, volume,"","",new Date(),null,Boolean.FALSE,Boolean.FALSE);
							}
						}
					}
				}
			}
		}else{
			Item item = items.get(random.nextInt(items.size()));//随即选取一个货品
			long quantity = getInvQuantity(loc.getUsedRate(),item.getMinPackageUnit().getVolume(),loc.getStowage().getVolume(),loc.getStowage().getQuantity());
			if(quantity!=0){
				ItemKey itemKey = getItemKey(item);
				this.receiving(loc.getId(),itemKey,quantity,item.getMinPackageUnit().getId(),
						null,barCode, weight, volume,"","",new Date(),null,Boolean.FALSE,Boolean.FALSE);
			}
		}
	}
	
	//得到托盘
	private Stock autoCreateInvForLP(Location loc,Item it){
		PutawayAllocator putawayAllocator = (PutawayAllocator)ac.getBean("putawayAllocator");
		//计算库位可放托盘数量
		int allowLPCount = putawayAllocator.calculateLocationCanPutAwayQty(loc, it.getLPPackageUnit()).intValue();
		if(allowLPCount<=0)
			return null;
		//获取满托数量（基本单位数量）
		double lpFullQty = 0;
		LPFormat lpFormat = it.getLPPackageUnit().getFitLPFormat(loc.getStowage().getHeight());
		if (lpFormat == null || (lpFormat.getTierQty() == 0 && lpFormat.getStackHighQty() == 0 && lpFormat.getHeight() == 0)) {
			return null;
		} else {
			lpFullQty = (lpFormat.getTierQty()* lpFormat.getStackHighQty()) * it.getLPPackageUnit().getConvertFigure();
		}
			
		Stock stock = EntityFactory.getEntity(Stock.class);
		stock.setWarehouse(loc.getWarehouse());
		stock.setLocation(loc);
		stock.setLP(codeManager.generateLP(loc.getWarehouse().getCode()));
		stock.setType(StockType.PALLET);
		stock.setItemQty(lpFullQty);
		stock.setWeight(stock.getItemQty()*it.getLPPackageUnit().getWeight());
		stock.setVolume(stock.getItemQty()*it.getLPPackageUnit().getVolume());
		stock.setLocationIndex(0);
		stock.setEnabled(true);
		stock.setInventoryQty(0);
		commonDao.store(stock);
		
		return stock;
	}
	
	private ItemKey getItemKey(Item item){
		SequenceGenerater sequenceGenerater = (SequenceGenerater)ac.getBean("sequenceGenerater");
		String soi = sequenceGenerater.generateSequence("INIT",12);

		ItemKey itemKey = new ItemKey("", item, new LotInfo(), new Date(), soi,null);
		if(item.getDefaultLotRule() != null && item.getDefaultLotRule().getLotRuleComponent().getTrackPropD1()){
			itemKey.getLotInfo().setPropD1(new Date());
		}
		ItemManager itemManager = (ItemManager)ac.getBean("itemManager");
		return itemManager.getItemKey(itemKey, Boolean.FALSE,null);
	}
	
	/*
	 * 随机决定其放置1个还是2个库位
	 * 如果库位是托盘库位，随机决定是否放,返回1则不放，返回2则放
	 * 方法：取得当前毫秒级，如果毫秒是偶数则返回2，是奇数则返回1
	 */
	private int getLocationNum(){
		long millis = System.currentTimeMillis();
		if(millis%2==1){
			return 1;
		}else{
			return 2;
		}
	}
	/**
	 * 根据货品体积和库位体积随即得到库存数量
	 * @param itemVolumn
	 * @param itemVolumn
	 * @param locVolumn
	 * @param maxQuantity:库位最大库存数量
	 * @return
	 */
	private long getInvQuantity(double usedRate,double itemVolumn,double locVolumn,double maxQuantity){
		if(locVolumn==0.0)
			return 0;
		if(itemVolumn>locVolumn)//如果库位体积小于货品体积
			return 0;
		Random random = new Random();
		if(maxQuantity>0.0)//库存数量不能大于库位最大库存数量
			return random.nextInt((new Double(maxQuantity*(1-usedRate/100)).intValue()));
		//如果货品体积为0，则返回0到10000之间的随即整数
		if(itemVolumn==0.0)
			return random.nextInt(10000);
		return random.nextInt((new Double((locVolumn*(1-usedRate/100))/itemVolumn)).intValue());
	}
	
	/**
	 * 移除托盘与关联对象间关系
	 * @param lp
	 */
	private void removeLPRelations(Stock lp) {
		//MoveDocDetail
//		List mdds = commonDao.findByQuery("FROM MoveDocDetail mdd "+
//				"WHERE mdd.moveDoc.warehouse.id = " + lp.getWarehouse().getId() +
//				" AND (mdd.srcLP.id = " + lp.getId() + " OR mdd.dstLP.id = " + lp.getId() + ")");
//		for (Object obj : mdds) {
//			MoveDocDetail mdd = (MoveDocDetail) obj;
//			if (mdd.getSrcLP() != null && mdd.getSrcLP().getId().equals(lp.getId())) {
//				mdd.setSrcLP(null);
//			}
//			if (mdd.getDstLP() != null && mdd.getDstLP().getId().equals(lp.getId())) {
//				mdd.setDstLP(null);
//			}
//		}
//		//TaskLog
//		List logs = commonDao.findByQuery("FROM TaskLog tl "+
//				"WHERE tl.srcLoc.warehouse.id = " + lp.getWarehouse().getId() +
//				" AND (tl.srcLP.id = " + lp.getId() + " OR tl.dstLP.id = " + lp.getId() + ")");
//		for (Object obj : logs) {
//			TaskLog log = (TaskLog) obj;
//			if (log.getSrcLP() != null && log.getSrcLP().getId().equals(lp.getId())) {
//				log.setSrcLP(null);
//			}
//			if (log.getDstLP() != null && log.getDstLP().getId().equals(lp.getId())) {
//				log.setDstLP(null);
//			}
//		}
//		//Task
//		List tasks = commonDao.findByQuery("FROM Task task "+
//				"WHERE task.srcLoc.warehouse.id = " + lp.getWarehouse().getId() +
//				" AND (task.srcLP.id = " + lp.getId() + " OR task.dstLP.id = " + lp.getId() + ")");
//		for (Object obj : tasks) {
//			Task task = (Task) obj;
//			if (task.getSrcLP() != null && task.getSrcLP().getId().equals(lp.getId())) {
//				task.setSrcLP(null);
//			}
//			if (task.getDstLP() != null && task.getDstLP().getId().equals(lp.getId())) {
//				task.setDstLP(null);
//			}
//		}
//		
//		lp.setEnabled(Boolean.FALSE);
//		commonDao.delete(lp);
	}

	public void countAdjust(CountRecord countRecord) {
		Location countLocation = (Location) commonDao.findByNamedQueryUniqueResult("getLocationsByType",
				new String[]{"type","warehouseId"},new Object[]{LocationType.COUNT, 
				countRecord.getCountPlan().getWarehouse().getId()});
		if (countLocation == null) {
			throw new BusinessException("count.location.none");
		}

		double deltaQuantity = countRecord.getDeltaQuantity();
		//对指定Location和itemKey的库存按照存货日期升序排列，调整日期最早的库存（减少费用计算时因存货日期导致的问题）
		ItemKeyInventory itemKeyInventory = getItemKeyInventory(countRecord.getLocation().getWarehouse(), 
				countRecord.getItemKey());
		List<Inventory> inventories = new ArrayList<Inventory>();
		for (Inventory inv : itemKeyInventory.getInventories()) {
			if (inv.getLocation().equals(countRecord.getLocation()) 
					&& ((inv.getLP()==null && countRecord.getLP()==null)
							|| (inv.getLP()!=null && inv.getLP().getLP().equals(countRecord.getLP())))) {
				inventories.add(inv);
			}
		}

		//原有库存增加或减少
		if (inventories.size()>0 && deltaQuantity<0) {
			Collections.sort(inventories, new BeanComparator("storageDate"));
			for (Inventory inventory : inventories) {
				//对inventory逐一调整（如果一个inventory数量不够扣减）
				//盘点库位上抹除托盘信息
				if (inventory.getQtyOfMasterPack()+deltaQuantity<0) {
					adjustInventoryAdd(countLocation, inventory.getItemKeyInventory().getItemKey(), 
							inventory.getQtyOfMasterPack(), inventory.getPackageUnit().getItem().getMinPackageUnit(), null, 
							inventory.getStatus(), inventory.getStorageDate(), inventory.getSOI(), 
							InventoryLogType.MOVE, Inventory.COUNT_ADJUST, null, 
							countRecord.getCountPlan().getCode(),inventory.isBeLock(),inventory.isBeReject());
					adjustInventoryUpdate(inventory, 0, 
							InventoryLogType.MOVE, Inventory.COUNT_ADJUST);
					deltaQuantity += inventory.getQtyOfMasterPack();
				} else {
					adjustInventoryAdd(countLocation, inventory.getItemKeyInventory().getItemKey(), 
							-deltaQuantity, inventory.getPackageUnit().getItem().getMinPackageUnit(), null, 
							inventory.getStatus(), inventory.getStorageDate(), inventory.getSOI(), 
							InventoryLogType.MOVE, Inventory.COUNT_ADJUST, null, 
							countRecord.getCountPlan().getCode(),inventory.isBeLock(),inventory.isBeReject());
					adjustInventoryUpdate(inventory, inventory.getQtyOfMasterPack()+deltaQuantity, 
							InventoryLogType.MOVE, Inventory.COUNT_ADJUST);
					deltaQuantity = 0;
				}
				if (deltaQuantity == 0) {
					break;
				}
			}
		} else {
			//新增库存
			if (deltaQuantity > 0) {
				double deltaPackQty = 0;
				if (countRecord.getPackageUnit().getPrecision() == 0) {
					deltaPackQty = Math.ceil(deltaQuantity / countRecord.getPackageUnit().getConvertFigure());
				} else {
					deltaPackQty = DoubleUtils.formatByPrecision(deltaQuantity / countRecord.getPackageUnit().getConvertFigure(), 
							countRecord.getPackageUnit().getPrecision());
				}
				Stock countLP = getStockWithNew(countRecord.getLocation(), countRecord.getLP(), 
						countRecord.getPackageUnit(), deltaPackQty);
				if (countLP!= null && !countLP.getLocation().equals(countRecord.getLocation())) {
					throw new BusinessException("LP.move.sameLocation");
				}
				
				//往盘点盈亏库位写入库存
				adjustInventoryAdd(countLocation, countRecord.getItemKey(), -deltaQuantity, 
						countRecord.getPackageUnit(), null, Inventory.STATUS_VALID, 
						countRecord.getCountPlan().getCountDate(), countRecord.getCountPlan().getCode(), 
						InventoryLogType.MOVE, Inventory.COUNT_ADJUST, null, countRecord.getCountPlan().getCode(),Boolean.FALSE,Boolean.FALSE);
				//往存货库位写入新增库存
				adjustInventoryAdd(countRecord.getLocation(), countRecord.getItemKey(), 
						deltaQuantity, countRecord.getPackageUnit(), countLP, Inventory.STATUS_VALID, 
						countRecord.getCountPlan().getCountDate(), countRecord.getCountPlan().getCode(), 
						InventoryLogType.MOVE, Inventory.COUNT_ADJUST, null, countRecord.getCountPlan().getCode(),Boolean.FALSE,Boolean.FALSE);
			}
		}
	}
	
	public void editInventoryStatus(List<Long> inventoryIds,String status){
		 for(Long id:inventoryIds){
			 Inventory inv =commonDao.load(Inventory.class, id);
			 if(inv.getLocation().getType().equals(LocationType.SHIP)||inv.getLocation().getType().equals(LocationType.RECEIVE)){
				 continue;
			 }
			 if(inv.getQueuedQuantity()>0){
				 throw new BusinessException("选中记录数量被占用");
			 }
			 String hql="from Inventory inv where inv.id!="+id
			 + " and inv.location.id="+inv.getLocation().getId()
			 + " and inv.itemKeyInventory.id="+inv.getItemKeyInventory().getId()
			 + " and inv.packageUnit.id="+inv.getPackageUnit().getId()
			 + " and to_char(inv.storageDate,'yyyy-mm-dd')='"+DateUtil.formatDateYMDToStr(inv.getStorageDate())+"'";
			if(inv.getSOI()!=null){
				hql+=" and inv.SOI='"+inv.getSOI()+"'";
			}else{
				hql+=" and inv.SOI is null";
			}
			if(inv.getLP()!=null){
				hql+=" and inv.LP.id="+inv.getLP().getId();
			}else{
				hql+=" and inv.LP.id is null";
			}
			if(status!=null){
				hql+=" and inv.status='"+status+"'";
			}else{
				hql+=" and inv.status is null";
			}
			double  qty= inv.getAvaliableQuantity();
			double oldQty=inv.getQtyOfMasterPack()-qty;
			List<Inventory> invs=this.commonDao.findByQuery(hql);
			if(invs.size()>0){
				Inventory newInv=invs.get(0);
				newInv.add(qty,0,0);
				InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, 1, null, inv.getLocation(), 
						(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
						qty,	inv.getPackageUnit(), inv.getStatus(), null,"调整为"+status, null ,inv.getZone());
			}
			if(invs.size()>0){
				InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, -1, null, inv.getLocation(), 
						(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
						oldQty,	inv.getPackageUnit(), inv.getStatus(), null,"调整为"+status, null ,inv.getZone());
				if(oldQty<=0){
					this.commonDao.delete(inv);
				}else{
					inv.remove(qty, 0, 0);
				}
			}else{
				InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, 0, null, inv.getLocation(), 
						(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
						qty,	inv.getPackageUnit(), inv.getStatus(), null,"调整为"+status, null ,inv.getZone());
				inv.setStatus(status);
				this.commonDao.store(inv);
			}
//			 
////			 inventory.setRemark(remark);
//			double  qty= inv.getAvaliableQuantity();
//			double oldQty=inv.getQtyOfMasterPack()-qty;
//			adjustInventoryAddWithNoLog(inv.getLocation(), inv.getItemKeyInventory().getItemKey(), qty, inv.getPackageUnit(), 
//					inv.getLP(), inv.getStatus(), inv.getStorageDate(), inv.getSOI(), Boolean.FALSE);
//			InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, 1, null, inv.getLocation(), 
//					(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
//					qty,	inv.getPackageUnit(), inv.getStatus(), null,"调整为"+status, null );
//			//扣减原批次库存
//			 adjustInventoryUpdateWithNoLog(inv, oldQty);
			
		 }
	 }
	
	public void confirmMoveTrans(List<Long> moveObjectIds){
		for(Long id:moveObjectIds){
			MoveObject obj=this.commonDao.get(MoveObject.class, id);
			List<MoveObjectDetail> details=commonDao.findByQuery("from MoveObjectDetail d where d.moveObject.id="+id);
			for(MoveObjectDetail d:details){
				this.companyTrans(d.getInvId(), obj.getCompanyB().getId(), d.getOrderQuantity(),"Move_Trans");
				d.setMoveQuantity(d.getOrderQuantity());
				this.commonDao.store(d);
			}
			obj.setMoveQuantity(obj.getOrderQuantity());
			obj.setStatus("CLOSE");
			this.commonDao.store(obj);
		}
	}

	@Override
	public void moveToInvBatch(List<Long> ids,Long locId){
		for(Long id:ids){
		   Inventory inv =this.commonDao.get(Inventory.class, id);
		   if(inv.getQueuedQuantity()>0){
			   throw new BusinessException("选中记录数量被占用");
		   }else if(!inv.getLocation().getType().equals(LocationType.TRANSIT)&&!inv.getLocation().getType().equals(LocationType.STORAGE)){
			   throw new BusinessException("选中记录库位不可用");
		   }else if(inv.getLocation().getId().equals(locId)){
			   throw new BusinessException("选中记录原库位和目标库位一致");
		   }else{
			    Location dstLoc=this.commonDao.get(Location.class, locId);
			    ItemKeyInventory iki=inv.getItemKeyInventory();
			   // System.out.println(iki.getId()+"=="+iki.getInventories().size()+"===="+inv.getId());
			    Inventory destInv= iki.isInventoryNew(dstLoc, inv.getMasterPackUnit(), 
						null, null,inv.getStatus(), inv.getStorageDate(), inv.getSOI(),inv.isBeLock(),inv.isBeReject());
			    if(destInv!=null){
			    	destInv.add(inv.getAvaliableQuantity(),0,0);
			    }else{
			    	 inv.setLocation(dstLoc);
					 this.commonDao.store(inv);
			    }
			    //对目标库存记录库存日志
			    addInventoryLog(InventoryLogType.MOVE, 1, null, dstLoc, 
			      (inv.getLP()==null?null:inv.getLP().getLP()), inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), 
			      inv.getSOI(), inv.getQuantity(), inv.getPackageUnit(), inv.getStatus(), null, null, null,inv.getZone());
			    //对目标库存记录库存日志
			    addInventoryLog(InventoryLogType.MOVE, -1, null, inv.getLocation(), 
			      (inv.getLP()==null?null:inv.getLP().getLP()), inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), 
			      inv.getSOI(), inv.getQuantity(), inv.getPackageUnit(), inv.getStatus(), null, null, null,inv.getZone());
			    if(destInv!=null){
			    	iki.getInventories().remove(inv);
			    	//this.commonDao.delete(inv);
			    }
		   }
		 }
	}
	
	

	@Override
	public void invLock(List<Long> ids, boolean beLock, String status) {
		String newLock=beLock==Boolean.TRUE?"是":"否";
		for(Long id :ids){
			Inventory inv=this.load(Inventory.class, id);
			String oldLock=inv.isBeLock()==Boolean.TRUE?"是":"否";
			String oldS=inv.getStatus();
			Location loc=inv.getLocation();
			if(inv.getQueuedQuantity()>0){
				 throw new BusinessException("占用数量不为0，不能锁定");
			}
			if(loc.getType().equals(LocationType.RECEIVE)||loc.getType().equals(LocationType.SHIP)){
				 throw new BusinessException("月台库存，不能锁定");
			}
			if(beLock){
				inv.setBeLock(true);
			}else{
				inv.setBeLock(false);
			}
			if(status!=null&&!status.equals("")){
				inv.setStatus(status);
			}
			commonDao.store(inv);
			InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, -1, null, inv.getLocation(), 
					(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
					inv.getQuantity(),inv.getPackageUnit(), oldS, null,"锁定/解锁设置:"+oldLock, null,inv.getZone() );
			InventoryLog log2 = addInventoryLog(InventoryLogType.MODIFY_STATUS, 1, null, inv.getLocation(), 
					(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
					inv.getQuantity(),inv.getPackageUnit(), inv.getStatus(), null,"锁定/解锁设置:"+newLock, null ,inv.getZone());
		}
	}

	@Override
	public void invLpLock(List<Long> ids, boolean beReject, String status) {
		String newLock=beReject==Boolean.TRUE?"是":"否";
		for(Long id :ids){
			Inventory inv=this.load(Inventory.class, id);
			String oldLock=inv.isBeReject()==Boolean.TRUE?"是":"否";
			String oldS=inv.getStatus();
			Location loc=inv.getLocation();
			if(inv.getQueuedQuantity()>0){
				 throw new BusinessException("占用数量不为0，不能标记不良品");
			}
			if(loc.getType().equals(LocationType.RECEIVE)||loc.getType().equals(LocationType.SHIP)){
				 throw new BusinessException("月台库存，不能标记不良品");
			}
			if(beReject){
				inv.setBeReject(true);
			}else{
				inv.setBeReject(false);
			}
			if(status!=null&&!status.equals("")){
				inv.setStatus(status);
			}
			commonDao.store(inv);
			InventoryLog log1 = addInventoryLog(InventoryLogType.MODIFY_STATUS, -1, null, inv.getLocation(), 
					(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
					inv.getQuantity(),inv.getPackageUnit(), oldS, null,"良品/不良品设置:"+oldLock, null ,inv.getZone());
			InventoryLog log2 = addInventoryLog(InventoryLogType.MODIFY_STATUS, 1, null, inv.getLocation(), 
					(inv.getLP()==null?null:inv.getLP().getLP()),inv.getItemKeyInventory().getItemKey(), inv.getStorageDate(), inv.getSOI(), 
					inv.getQuantity(),inv.getPackageUnit(), inv.getStatus(), null,"良品/不良品设置:"+newLock, null ,inv.getZone());
		}
		
	}
	
	public Inventory getInventoryNew(ItemKey itemkey,WarehouseArea zone,Location location, String billCode){
		String type="0";
		//KAMS的库位字段不需要
		if(zone.getWarehouse().getId().equals(1L)){
			type="2";
		}else{
			type="1";
		}
		String hql="from Inventory inv where inv.itemKey.id="+itemkey.getId()+" "
				+ " and inv.zone.id="+zone.getId();
		//type 1.VMI正常入库，2.KAMS入库，3.线边入库，4.备货入库
		if(zone.getCode().indexOf("-SL")>0) {
			hql+=" and inv.barCode='XB' ";
			//线边固定放在线边库位,目前数据没有放，等刷新
			//hql+=" and inv.location.code='"+SysCode.XB_LOC+"'";
		}
		//备货固定放在备货库位
		hql+=" and inv.location.id="+location.getId();
//		if(type.equals("1")){
//			if(location!=null){
//				hql+=" and inv.location.id="+location.getId();
//			}
//		}else{
//			if(location.getType().equals(LocationType.SHIP)){
//				hql+=" and inv.location.id="+location.getId();
//			}else{
//				hql+=" and inv.location.type!='SHIP' and inv.location";
//			}
////			if(location!=null){
////				hql+=" and (inv.location.id="+location.getId()+" or inv.location.id is null)";
////			}
//		}
		List<Inventory> invs=this.commonDao.findByQuery(hql);
		if(invs.size()>0){
			Inventory inv=invs.get(0);
			if(invs.get(0).getLocation()==null){
				inv.setLocation(location); 
				this.commonDao.store(inv);
			}
			return inv;
		}else{
			Inventory dbInv=EntityFactory.getEntity(Inventory.class);
//			if(type.equals("1")){
			dbInv.setLocation(location);
//			}
			dbInv.setItemKey(itemkey);
//			dbInv.setStatus(status);
			dbInv.setZone(zone);
			if(zone.getCode().indexOf("-SL")>0) {
				dbInv.setBarCode("XB");
			}
			itemkey.getInventories().add(dbInv);
			this.commonDao.store(dbInv);
			return dbInv;
		}
	}
	
	public Inventory adjustInventoryAdd(ItemKey itemkey,WarehouseArea zone,Location location, double quantity, 
			String status,Boolean lock,Boolean reject) {
		Inventory inventory = getInventoryNew(itemkey,zone,location, status);
		inventory.add(quantity,0,0);
		if (inventory.isNew()) {
			itemkey.getInventories().add(inventory);
		} else {
			if (inventory.getQtyOfMasterPack() == 0 && inventory.getQueuedQuantity() == 0) {
				itemkey.getInventories().remove(inventory);
			}
		}
		this.commonDao.store(inventory);
		return inventory;
	}
	
	public Inventory ship(ItemKey itemkey,Location location, double quantity,String status) {
		List<Inventory> invs=this.commonDao.findByQuery("from Inventory inv where inv.itemKey.id="+itemkey.getId()+" and inv.location.id="+location.getId());
		if(invs.size()>0){
			Inventory inventory=invs.get(0);
			inventory.remove(quantity,0,0);
			if (inventory.getQtyOfMasterPack() == 0 && inventory.getQueuedQuantity() == 0) {
				itemkey.getInventories().remove(inventory);
			}
			return inventory;
		}else{
			return null;
		}
		
	}
	
	@Override
	//查找库存存不存在
	public Inventory findInventory(ItemKey itemkey,WarehouseArea zone,Location location,String billCode,String type,Location zzkw){
		//type 1备货，2备货确认-1，3备货确认+1，4备货-1，5备货+1，5发运，6取消发运
		String hql="from Inventory inv where inv.itemKey.id="+itemkey.getId()+" "
				+ " and inv.zone.id="+zone.getId();
		//type 1.VMI正常入库，2.KAMS入库，3.线边入库，4.备货入库
		if(zone.getCode().indexOf("-SL")>0) {
			hql+=" and inv.barCode='XB' ";
			//线边固定放在线边库位,目前数据没有放，等刷新
//			hql+=" and inv.location.code='"+SysCode.XB_LOC+"'";
			if(zone.getHckw()==null){
				throw new BusinessException("维护库区对应线边待投料库位");
			}
//			hql+=" and inv.location.id='"+zone.getHckw().getId()+"'";
//			if(!type.equals(SysCode.CK_FP2)){
//				hql+=" and inv.zzkw.id="+zzkw.getId();
//			}
		}
		hql+=" and inv.location.id="+location.getId();
		//备货固定放在备货库位
		if(type.equals(SysCode.CK_FP2)){
			hql+=" and inv.location.type!='SHIP'";
		}else if(type.equals(SysCode.CK_TH1)){
			hql+=" and inv.location.type='SHIP'";
		}else if(type.equals(SysCode.CK_TH2)){
			hql+=" and inv.location.type!='SHIP'";
		}else if(type.equals(SysCode.CK_BH1)){
			hql+=" and inv.location.type!='SHIP' and inv.quantity>0";// and inv.queuedQuantity>0 ";
		}else if(type.equals(SysCode.CK_BH2)){
			hql+=" and inv.location.type='SHIP'";
		}else if(type.equals(SysCode.CK_FY1)){
			hql+=" and inv.location.type='SHIP'";
		}else if(type.equals(SysCode.CK_FY2)){
			hql+=" and inv.location.type!='SHIP'";
		}else if(type.equals(SysCode.RK_SH1)||type.equals(SysCode.RK_SH2)){
			hql+=" and inv.location.type!='SHIP' ";
			if(zone.getCode().indexOf("-SL")>0) {
				hql+=" and inv.zzkw.id="+zzkw.getId();
			}
		}else if(type.equals(SysCode.XB1)||type.equals(SysCode.XB2)||type.equals(SysCode.ZZKW_TRAN)||type.equals(SysCode.ZZ_TL)||type.equals(SysCode.HC_TL)){
			hql+=" and  inv.location.type!='SHIP' and inv.zzkw.id="+zzkw.getId();
		}
		List<Inventory> invs=this.commonDao.findByQuery(hql);
		if(invs.size()>0){
			Inventory inv=invs.get(0);
			if(invs.get(0).getLocation()==null){
				inv.setLocation(location);
				this.commonDao.store(inv);
			}
			return inv;
		}else{
			if(type.equals(SysCode.RK_SH1)||type.equals(SysCode.ZZKW_TRAN)||type.equals(SysCode.XB1)
					||type.equals(SysCode.ZZ_TL)||type.equals(SysCode.HC_TL)){
				Inventory dbInv=EntityFactory.getEntity(Inventory.class);
				dbInv.setLocation(location);
				dbInv.setItemKey(itemkey);
				dbInv.setZone(zone);
				if(zone.getCode().indexOf("-SL")>0) {
					dbInv.setBarCode("XB");
					dbInv.setZzkw(zzkw);
				}
				itemkey.getInventories().add(dbInv);
				this.commonDao.store(dbInv);
				return dbInv;
			}else{
				return null;
			}
		}
	}
	
	@Override
	public InventoryLog addInventoryLog(String logType, int incOrDec, WarehouseArea zone,Location location,String relatedBill, 
			 ItemKey itemKey,  double occurQuantity, String LP,String operator,Long referenceLog, String description,String operDesc,String bhr,String cph,Location zzkw) {
		InventoryLog log=EntityFactory.getEntity(InventoryLog.class);
		log.setWarehouse(zone.getWarehouse());
		log.setZone(zone);
		log.setLogType(logType);
		log.setIncOrDec(incOrDec);
		log.setRelatedBill(relatedBill);
		log.setLocation(location);
		log.setItemKey(itemKey);
		log.setOccurQuantity(occurQuantity);
		log.setTph(LP);
		log.setBhr(bhr);
		log.setCph(cph);
		log.setReferenceLog(referenceLog);
		log.setOperator(operator);
		log.setOccurTime(new Date());
		log.setDescription(description);
		log.setZzkw(zzkw);
		log.setOperDes(operDesc);
		this.commonDao.store(log);
		return log;
	}
}