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

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

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.Location;
import com.dev.swms.server.model.base.LotInfo;
import com.dev.swms.server.model.base.NewLotInfo;
import com.dev.swms.server.model.base.SignFile;
import com.dev.swms.server.model.base.Structure;
import com.dev.swms.server.model.base.PackageUnit;
import com.dev.swms.server.model.base.Store;
import com.dev.swms.server.model.base.Warehouse;
import com.dev.swms.server.model.inventory.Inventory;
import com.dev.swms.server.model.inventory.InventoryApply;
import com.dev.swms.server.model.inventory.InventoryApplyDetail;
import com.dev.swms.server.model.inventory.ItemKeyInventory;
import com.dev.swms.server.model.inventory.Stock;
import com.dev.swms.server.model.inventory.Task;
import com.dev.swms.server.model.inventory.TaskType;
import com.dev.swms.server.model.receiving.ASN;
import com.dev.swms.server.model.receiving.ASNDetail;
import com.dev.swms.server.model.receiving.ASNStatus;
import com.dev.swms.server.model.receiving.MoveDoc;
import com.dev.swms.server.model.receiving.MoveDocDetail;
import com.dev.swms.server.model.receiving.MoveDocStatus;
import com.dev.swms.server.model.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.ItemStorageRule;
import com.dev.swms.server.model.rules.ItemSupplyRule;
import com.dev.swms.server.model.shipping.Label;
import com.dev.swms.server.model.shipping.LabelDetail;
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.service.GlobalParamUtils;
import com.dev.swms.server.service.base.ItemManager;
import com.dev.swms.server.service.interfaceLog.InterfaceLogManager;
import com.dev.swms.server.service.inventory.InventoryManager;
import com.dev.swms.server.service.picking.allocate.AutoAllocator;
import com.dev.swms.server.service.receiving.MoveDocManager;
import com.dev.swms.server.service.receiving.PutawayAllocator;
import com.dev.swms.server.service.sequence.BussinessCodeManager;
import com.dev.swms.server.utils.DoubleUtils;
import com.dev.swms.server.web.filter.WarehouseHolder;
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;

public class DefaultMoveDocManager extends DefaultBaseManager implements
		MoveDocManager {
	protected final InventoryManager inventoryManager;
	protected final PutawayAllocator putawayAllocator;
	protected final BussinessCodeManager codeManager;
	protected final InterfaceLogManager logManager;
	protected final ItemManager itemManager;
	protected final AutoAllocator autoAllocator;

	public DefaultMoveDocManager(InventoryManager manager,
			PutawayAllocator allocator, BussinessCodeManager manager2,
			InterfaceLogManager manager3, ItemManager manager4,AutoAllocator autoAllocator) {
		super();
		inventoryManager = manager;
		putawayAllocator = allocator;
		codeManager = manager2;
		logManager = manager3;
		itemManager = manager4;
		this.autoAllocator=autoAllocator;
	}

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.receiving.MoveDocManager#moveTo(java.lang.Long, java.lang.Long)
	 */
	@SuppressWarnings("unchecked")
	public void moveTo(Long moveDocId, Long workerId) {
		List<Task> tasks = commonDao.findByQuery("FROM Task task WHERE task.moveDocDetail.moveDoc.id = " 
				+ moveDocId + " AND task.planQuantityMU-task.movedQuantityMU>0");
		for (Task task : tasks) {
			this.moveTo(task, workerId);
		}
	}
	
	public void moveTo(Task task, Long workId) {
		double moveQty = task.getPlanQuantityMU() - task.getMovedQuantityMU();
		if (moveQty > 0) {
			this.moveTo(task, workId, task.getDstLoc(), task.getPackageUnit().getId(), moveQty);
		}
	}
	
	public void taskMove(Task task, Long workId, Long dstLocId, Long packageUnitId, double quantity) {
		Location dstLoc = commonDao.load(Location.class, dstLocId);
		task = commonDao.load(Task.class, task.getId());
		if(dstLoc == null){
			dstLoc = task.getDstLoc();
		}
		PackageUnit pu = commonDao.load(PackageUnit.class, packageUnitId);
		double moveQty = task.getPlanQuantityMU() - task.getMovedQuantityMU();
		if (moveQty < quantity * pu.getConvertFigure()) {
			throw new BusinessException("task.move.quantity.error");
		}
		
		this.moveTo(task, workId, dstLoc, packageUnitId, quantity * pu.getConvertFigure());
	}
	
	/**
	 * 单一任务移位确认
	 * @param task 移位任务
	 * @param workId 移位人
	 * @param dstLoc 移位目标库位
	 * @param packageUnitId 移位包装
	 * @param quantity 移位数量（基本单位数量）
	 */
	private void moveTo(Task task, Long workId, Location dstLoc, Long packageUnitId, double quantity) {
		task = this.commonDao.load(Task.class,task.getId());
		if(!TaskType.MV_CROSS.equals(task.getType()) && dstLoc.getStowage()==null){
			throw new BusinessException("moveTo.dstLocation.getStowage.null");
		}
		
//		if (task.getMoveDocDetail().getMoveDoc().getPlanQuantity()
//				!= task.getMoveDocDetail().getMoveDoc().getAllocatedQuantity()) {
//			throw new BusinessException("moveTo.must.after.allocated.all");
//		}
		
		this.moveTo(task.getId(), dstLoc.getId(), 
				task.getDstLP() == null ? null : task.getDstLP().getId(), packageUnitId, 
				quantity, workId, task.getSrcLoc().getId());
	}

	@SuppressWarnings("unchecked")
	private void moveTo(Long taskId, Long dstLocationId, Long LP, Long packageUnitId, 
			Double movedQuantity, Long workId, Long srcLocId) {
		if (movedQuantity <= 0) {
			throw new BusinessException("task.move.quantity.error");
		}
		Task task = commonDao.load(Task.class, taskId);
		
		List<PickTicketDetail> ptds = commonDao.findByQuery("FROM PickTicketDetail ptd " +
				" WHERE ptd.applyDocDetailId = " + task.getMoveDocDetail().getId());
		
		Location realLoc = commonDao.load(Location.class, dstLocationId);
		PackageUnit unit = commonDao.load(PackageUnit.class, packageUnitId);
		Location dstLoc = task.getDstLoc();
		if (!realLoc.bePutAwayLock()) {	// 检查库位是否被锁定
			// 库存移位处理
			ItemKeyInventory itemKeyInventory = inventoryManager.getItemKeyInventory(
					task.getSrcLoc().getWarehouse(), task.getItemKey());
			List<Inventory> invs = itemKeyInventory.getInventories(task.getSrcLoc(), task.getSrcLP(), 
					task.getStorageDate(), task.getSOI(), task.getInventoryStatus());

			List<Inventory> pkgInvs = new ArrayList<Inventory>();
			for (Inventory inv : invs) {
				if (inv.getPackageUnit().equals(unit)) {
					pkgInvs.add(inv);
				}
			}
			invs.removeAll(pkgInvs);
			pkgInvs.addAll(invs);
			
			for (Inventory inv : pkgInvs) {
				//对满足条件库存逐一扣减，直到移位完毕
				if (inv.getQueuedQuantity()>0) {
					double toBeMovedQty = inv.getQueuedQuantity();
					if (movedQuantity <= inv.getQueuedQuantity()) {
						toBeMovedQty = movedQuantity;
					}
					// 对源库存取消分配
					inv.unallocate(toBeMovedQty, dstLoc, task.getDstLP());
					// 移位确认
					inventoryManager.moveInventory(inv.getId(), dstLocationId, LP, 
							toBeMovedQty, unit.getId(), task.getId(), workId);
					
					//对已补货待分配数量进行分配
					if (ptds != null && ptds.size() > 0) {
						pickingAllocate(ptds, itemKeyInventory, dstLocationId, LP, 
								inv.getStorageDate(), inv.getSOI(), inv.getStatus());
					}

					movedQuantity -= toBeMovedQty;
				}
				if (movedQuantity <= 0) {
					break;
				}
			}
			if (movedQuantity > 0) {
				throw new BusinessException("move.inventory.none");
			}
		}
		updateReceivedRecordStatus(task.getMoveDocDetail().getMoveDoc());
	}
	
	private void pickingAllocate(List<PickTicketDetail> ptds, ItemKeyInventory itemKeyInventory,
			Long locationId, Long LP, Date storageDate, String soi,	String status) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Set<Inventory> invs = itemKeyInventory.getInventories();
		for (Inventory inv : invs) {
			if (inv.getLocation().getId().equals(locationId) 
					&& sdf.format(inv.getStorageDate()).equals(sdf.format(storageDate)) 
					&& soi.equals(inv.getSOI())
					&& ((LP == null && inv.getLP() == null) || (inv.getLP() != null && LP != null && inv.getLP().getId().equals(LP)))
					&& inv.getStatus().equals(status)) {
				
				for (PickTicketDetail ptd : ptds) {
					if (inv.getAvaliableQuantity() >  ptd.getUnallocateQuantity()) {
						inv.allocate( ptd.getUnallocateQuantity(), null, null);
						ptd.getPickTicket().allocate(null,ptd, inv,  ptd.getUnallocateQuantity());
						ptd.setApplyDocDetailId(null);
					} else {
						ptd.getPickTicket().allocate(null,ptd, inv, inv.getAvaliableQuantity());
						inv.allocate(inv.getAvaliableQuantity(), null, null);
					}
					if (inv.getAvaliableQuantity() <= 0) {
						break;
					}
				}
			}
		}
	}

	/**
	 * 关闭补货单
	 * */
	@SuppressWarnings("unchecked")
	public void closeSupplyDoc(List<Long> moveDocIds){
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			String barCode=null;
			//取得task集合
			List tasks = this.commonDao.findByQuery("from Task task where task.moveDocDetail.moveDoc.id =" +moveDoc.getId());
			for (Object o : tasks) {
				Task task = (Task) o;
				double quantity = task.getPlanQuantityMU() - task.getMovedQuantityMU();
				if (quantity > 0) {
					ItemKeyInventory itemKeyInventory = inventoryManager.getItemKeyInventory(
							task.getSrcLoc().getWarehouse(), task.getItemKey());
					Inventory inventory = itemKeyInventory.getInventoryWithException(task.getSrcLoc(), 
							task.getPackageUnit(), task.getSrcLP(), barCode,task.getInventoryStatus(), 
							task.getStorageDate(), task.getSOI());
					inventory.unallocate(quantity, task.getDstLoc(), task.getDstLP());

					task.unallocateMove(quantity);
					if (task.getPlanQuantityMU() == .0) {
						task.getMoveDocDetail().getTasks().remove(task);
					}
				}
			}
			moveDoc.setStatus(MoveDocStatus.CLOSE);
		
		}
		
	}
	
	/**
	 * 删除补货单
	 * Author:yufei.ge
	 * */
	public void deleteSupplyDoc(List<Long> moveDocIds){
		String errMsg = "";
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			if(MoveDocStatus.OPEN.equals(moveDoc.getStatus())){
				this.commonDao.delete(moveDoc);
				errMsg+=moveDoc.getCode()+" 单据删除成功;";
			}
			else
				errMsg+=moveDoc.getCode()+" 单据删除失败;";
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
	}
	

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.receiving.MoveDocManager#inactiveSupplyDoc(java.util.List)
	 */
	public void inactiveSupplyDoc(List<Long> moveDocIds) {
		String errMsg="";
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			autoAllocator.unallocate(moveDoc);
			if(moveDoc.getAllocateQuantity() == 0)
				//部分分配成功
				errMsg+=moveDoc.getCode()+" 反激活成功;";
			else 
				// 分配失败
				errMsg+=moveDoc.getCode()+" 反激活失败;";
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
	}

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.receiving.MoveDocManager#cancel(java.util.List)
	 */
	@SuppressWarnings("unchecked")
	public void cancel(List<Long> moveDocIds) {
		String errMsg = "";
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			if (moveDoc.cancel()) {
				errMsg+=moveDoc.getCode()+" 单据取消成功;";
			}
			else
				errMsg+=moveDoc.getCode()+" 单据取消失败;";
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
	}
	/**
	 * 删除移位单
	 * Author:yufei.ge
	 * */
	@SuppressWarnings("unchecked")
	public void deleteMoveDoc(List<Long> moveDocIds) {
		String errMsg = "";
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			if (MoveDocStatus.OPEN.equals(moveDoc.getStatus())){
				this.commonDao.delete(moveDoc);
				errMsg+=moveDoc.getCode()+" 单据删除成功;";
			}
			else
				errMsg+=moveDoc.getCode()+" 单据删除失败;";
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
		
	}
	

	@SuppressWarnings("unchecked")
	private void updateReceivedRecordStatus(MoveDoc moveDoc) {
		List<ReceivedRecord> records = commonDao.findByNamedQuery("getReceivedRecordsByMoveDoc", 
				new String[] {"code", "warehouseId", "companyId"}, 
				new Object[] {moveDoc.getCode(), moveDoc.getWarehouse().getId(), 
				moveDoc.getCompany().getId()});
		for (ReceivedRecord rec : records) {
			rec.setBeMoved(Boolean.TRUE);
		}
	}

	/*
	 * (non-Javadoc)
	 * @see com.dev.swms.server.service.receiving.MoveDocManager#unallocate(java.util.List)
	 */
	public void unallocate(List<Long> moveDocIds) {
		for (Long id : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, id);
			putawayAllocator.unallocate(moveDoc);
		}
	}

	public MoveDocDetail getMoveDocDetailByItem(Long moveDocId, String itemCode) {
		MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
		for (MoveDocDetail detail : moveDoc.getDetails()) {
			// 只能返回未上架明细
			if ((detail.getItemKey().getItem().getCode().equals(itemCode))
					&& (detail.getMoveQuantity() < detail.getAllocateQuantity())
					&& "".equals(detail.getDstLP())) {
				return detail;
			}
		}
		return null;
	}

	public MoveDocDetail getMoveDocDetailByItemKey(Long moveDocId,
			Long itemKeyId) {
		MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
		for (MoveDocDetail detail : moveDoc.getDetails()) {
			// 只能返回未上架明细
			if ((detail.getItemKey().getId().equals(itemKeyId))
					&& (detail.getMoveQuantity() < detail.getAllocateQuantity())) {
				return detail;
			}
		}
		return null;
	}

	/**
	 * 激活(一条或多条移位计划) 移位计划激活后，系统要自动锁定 源库存数量 和 目标库位待上架数量
	 */
	public void inactiveMoveDoc(List<Long> moveDocIds) {
		String errMsg = "";
		for (Long moveDocId : moveDocIds) {
			MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
			// 对指定的上架计划按规定策略做自动分配
			putawayAllocator.unallocate(moveDoc);
			if(moveDoc.getAllocateQuantity() == 0)
				errMsg+=moveDoc.getCode()+" 反激活成功;";
			else 
				errMsg+=moveDoc.getCode()+" 反激活失败;";
			
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
	}
	
	/**
	 * 保存新增的移位计划
	 */
	public void storeMoveLP(MoveDoc moveDoc) {		
		//根据全局变量得到收货单的billTypeSOI属性，用于上架计划的分配 zongxing.zeng
		BillType billType = (BillType) this.commonDao.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
						new String[] {"code"}, 
						new Object[] {MoveDoc.MV_MOVE });
		
		if (billType == null) {
			throw new BusinessException("无此单据类型!");
		}
		if (moveDoc.isNew()) {
//			moveDoc.setCode(this.codeManager.getCodeByBillType(billType,WarehouseHolder.getWarehouse().getId()));
			moveDoc.setCode(this.codeManager.getCodeForYm("MV",5));
			moveDoc.setWarehouse(WarehouseHolder.getWarehouse());
			moveDoc.setStatus(MoveDocStatus.OPEN);
			moveDoc.setUserTracking();
		}
		moveDoc.setBillType(billType);
		this.store(moveDoc);
	}

	/**
	 * 手工新增移位明细
	 * @param moveDocId : 上架ID
	 * @param inventoryId : 库存ID
	 * @param destLocationId : 目标库位ID
	 * @param packageUnitId : 移位包装ID
	 * @param quantity : 移位数量(包装数量)
	 */
	public void addMoveLPDetail(Long moveDocId, Long inventoryId,
			Long destLocationId, Long packageUnitId, Double quantity) {
		// 移位源库存
		Inventory inventory = commonDao.load(Inventory.class, inventoryId);
		PackageUnit pu=null;
		if(packageUnitId==null){
			pu=inventory.getPackageUnit();
		}else{
			pu = commonDao.load(PackageUnit.class, packageUnitId);
		}
		quantity = quantity * pu.getConvertFigure();
		// 如果移位数量大于库存可用数量
		if (quantity > inventory.getAvaliableQuantity() || quantity <= 0) {
			throw new BusinessException("movedoc.quantity.error");
		}
		
		// 移位计划
		MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);

		//如果页面上不指定目标库位，在激活时用上架策略进行分配
		Location location = null;
		if(null != destLocationId){
			location = commonDao.load(Location.class, destLocationId);
		}
		
		Stock dstLP = null;
		// 整托移位时托盘号保留
		if (inventory.getLP() != null && inventory.getLP().getInventoryQty() == quantity) {
			dstLP = inventory.getLP();
		}
		// 创建移位计划明细
		generateMoveDocDetail(moveDoc, inventory.getLocation(), inventory.getLP(), 
				location, dstLP, inventory.getItemKeyInventory().getItemKey(), 
				pu, quantity, inventory.getStatus(), inventory.getStorageDate(), inventory.getSOI());
		commonDao.store(moveDoc);
	}
	
	@Override
	public void addMoveLPDetails(Long moveDocId, Map invs) {
		Iterator it = invs.entrySet().iterator();
		while(it.hasNext()) {
		 	Map.Entry entry = (Map.Entry) it.next();	
			Long inventoryId=(Long) entry.getKey();
			List value=  (List) entry.getValue();
			String locationCode = String.valueOf(value.get(0));
			String qty = String.valueOf(value.get(1));
			if(locationCode!=null&&!locationCode.equals("-")){
				locationCode=locationCode.toUpperCase();
				if(locationCode.substring(0, 1).equals("-")){
					locationCode=locationCode.substring(1,locationCode.length());
				}
				List<Location> ls=this.commonDao.findByQuery("from Location l where upper(l.code)='"+locationCode+"'");
				if(ls.size()>0){
					this.addMoveLPDetail(moveDocId, inventoryId, ls.get(0).getId(), null, Double.parseDouble(qty));
				}else{
					throw new BusinessException(locationCode+"库位不存在");
				}
				putawayAllocator.allocate(moveDocId);
			}
			
		}
		
	}
	
	
	
	
	/**
	 * 根据传入参数自动创建移位计划明细
	 * @param moveDoc  移位计划
	 * @param inventory  移位源库存
	 * @param quantity  移位数量
	 * @param dstLoc  目标库位
	 * @param srcLoc  源库位
	 */
	private void generateMoveDocDetail(MoveDoc moveDoc, Location srcLoc,
			Stock srcLP, Location dstLoc, Stock dstLP, ItemKey itemKey,
			PackageUnit packageUnit, double quantity, String status, Date storageDate, String SOI) {
		MoveDocDetail detail = EntityFactory.getEntity(MoveDocDetail.class);
		// 设置商品属性
		detail.setItemKey(itemKey);
		// 设置包装单位
		detail.setPackageUnit(packageUnit);
		detail.setSrcLoc(srcLoc);
		detail.setSrcLP(srcLP);
		detail.setSrcLPCode(srcLP==null?null:srcLP.getLP());
		detail.setDstLoc(dstLoc);
		detail.setDstLP(dstLP);
		detail.setDstLPCode(dstLP==null?null:dstLP.getLP());
		detail.setMoveDoc(moveDoc);
		detail.setInventoryStatus(status);
		detail.setStorageDate(storageDate);
		detail.setSOI(SOI);
		detail.add(quantity);
		moveDoc.getDetails().add(detail);
	}

	/**
	 * 删除明细
	 * 
	 * @param moveDocId
	 *            移位计划ID
	 * @param moveDocDetailIds
	 *            移位计划明细ID集合（为null时表示整单明细全部删除）
	 */
	public void deleteMoveLPDetails(Long moveDocId, List<Long> moveDocDetailIds) {
		MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
		if (MoveDocStatus.OPEN.equals(moveDoc.getStatus())||MoveDocStatus.ALLOCATE.equals(moveDoc.getStatus())) {
			for (Long id : moveDocDetailIds) {
				MoveDocDetail detail = commonDao.load(MoveDocDetail.class, id);
				List<Task> ts=this.commonDao.findByQuery("from Task t where t.moveDocDetail.id=:moveDocDetailId",
						new String[]{"moveDocDetailId"},new Object[]{id});
				for(Task t:ts){
					putawayAllocator.unallocateTask(t);
				}
				moveDoc.removeDetail(detail);
			}
			commonDao.store(moveDoc);
		}
	}

	/**
	 * 手工修改移位明细
	 */
	public void editMoveLPDetail(Long moveDocId, MoveDocDetail moveDocDetail) {
		if (moveDocDetail.getPlanQuantity() <= 0) {
			throw new BusinessException("docDetail.add.quantityError");
		}
		double planQty = moveDocDetail.getPlanQuantity();
		Location dstLoc = moveDocDetail.getDstLoc();
		MoveDoc moveDoc = commonDao.load(MoveDoc.class, moveDocId);
		moveDocDetail = commonDao.load(MoveDocDetail.class, moveDocDetail.getId());
		double deltaQty = planQty - moveDocDetail.getPlanQuantity();

		if (MoveDocStatus.OPEN.equals(moveDoc.getStatus())) {
			moveDocDetail.setDstLoc(dstLoc);
			moveDocDetail.setPlanQuantity(planQty);
			moveDoc.setPlanQuantity(moveDoc.getPlanQuantity()
					+ deltaQty*moveDocDetail.getPackageUnit().getConvertFigure());
		}
	}
	
	/**
	 * 自动创建补货申请单
	 * 作者:yufei.ge
	 */
	@SuppressWarnings("unchecked")
	public void autoCreateApplyDoc(){
		 //查出安全库存规则里 库存下限，库存上限，补货仓库都不为空的补货仓库和货主的分组记录*/
		 List temp = commonDao.findByQuery("select rule.replenishmentWarehouse ,rule.item.company FROM ItemStorageRule rule WHERE rule.minStock is not NULL and rule.maxStock is not NULL and rule.replenishmentWarehouse is not NULL and rule.warehouse.id = "+WarehouseHolder.getWarehouse().getId()+" group by rule.replenishmentWarehouse,rule.item.company " );
		
		 if(temp.size()<1){
			 LocalizedMessage.addMessage("InventoryApplyDoc.autocreate.failed");
			 return;
		 }
		 Warehouse wh = null;
		 Structure company = null;
		 
		 for(Object o:temp){
			Object[] values = (Object[]) o;
			wh = (Warehouse)values[0];
			company = (Structure)values[1];
			
			//创建申请单
			storeInventoryApplyDoc(wh,company);
		 }	
	}
	
	/**
	 * 保存补货申请单以及明细
	 * 作者:yufei.ge
	 * */
	@SuppressWarnings("unchecked")
	public void storeInventoryApplyDoc(Warehouse wh,Structure company){
		double sum = 0;
		//创建申请单头
		InventoryApply inventoryApply = EntityFactory.getEntity(InventoryApply.class);
		 
		inventoryApply.setCode(codeManager.generateInventoryApplyCode(null));//申请单号 
		inventoryApply.setApplyWarehouse(WarehouseHolder.getWarehouse());//申请仓库
		inventoryApply.setAcceptWarehouse(wh);//受理仓库
		inventoryApply.setCompany(company);//所属客户
		 
		inventoryApply.setApplyDate(new Date());
		inventoryApply.setStatus(InventoryApply.INPUT);//初始状态设为'录入'
		inventoryApply.setInventoryApplyDetails(new HashSet<InventoryApplyDetail>());
		
		//查找隶属于指定补货仓库和货主的货品
		List<ItemStorageRule> rules  = commonDao.findByQuery("FROM ItemStorageRule rule WHERE  rule.maxStock is not NULL and rule.replenishmentWarehouse.id = "+wh.getId()+" and rule.item.company.id ="+ company.getId()+" and rule.warehouse.id = "+WarehouseHolder.getWarehouse().getId()+" and rule.minStock is not null");
		 
		//判断这些货品是否存在于库存中，如存在则判断其库存总量是否小于安全库存下限，如不存在则默认其库存量为0
		for(Object o:rules){
			ItemStorageRule isr = (ItemStorageRule)o;
			
			//计算当前仓库下指定货主的货物总数
			List tempQt = commonDao.findByQuery("select sum(inventory.qtyOfMasterPack) from Inventory inventory where inventory.itemKeyInventory.warehouse.id = "+WarehouseHolder.getWarehouse().getId()+" and inventory.itemKeyInventory.itemKey.item.id = "+isr.getItem().getId());
			String count=tempQt.get(0)==null?"0":tempQt.get(0).toString();
			
			//创建申请单明细
			if(isr.getMinStock()>Double.parseDouble(count)){
				InventoryApplyDetail iad = EntityFactory.getEntity(InventoryApplyDetail.class);
					 
				iad.setInventoryApply(inventoryApply);
				iad.setItem(isr.getItem());//货物
				iad.setNewLotInfo(new NewLotInfo());//批次属性
				iad.setPackageUnit(isr.getItem().getMinPackageUnit());//包装单位
				iad.setPlanQuantity(isr.getMaxStock()-Double.parseDouble(count));//申请数量=安全库存上限-当前库存总数
					 
				sum+=iad.getPlanQuantity();//计算申请数量总和
					 
				inventoryApply.getInventoryApplyDetails().add(iad);
			}
			
		 }
		 inventoryApply.setQuantity(sum);
		 this.commonDao.store(inventoryApply);
	}
	
	/**
	 * 向受理仓库发送补货申请单
	 * 作者:yufei.ge
	 * */
	public void sendApplyDoc(List<Long> ids){
		for(Long id:ids){
			 
			 InventoryApply inventoryApply = this.commonDao.load(InventoryApply.class,id);
			 if(!InventoryApply.CLOSED.equals(inventoryApply.getStatus())&&
				!InventoryApply.CANCEL.equals(inventoryApply.getStatus())&&
				InventoryApply.INPUT.equals(inventoryApply.getStatus()))
			 inventoryApply.setStatus(InventoryApply.APPLY);
		}
	}
	
	/**
	 * 根据补货申请单内容创建发货单
	 * 作者:yufei.ge
	 * */
	@SuppressWarnings("unchecked")
	public void createPickTicketByApplyDoc(List<Long> ids){
		for(Long id:ids){
			
			 InventoryApply inventoryApply = this.commonDao.load(InventoryApply.class,id);
			 
			 /* 判断单据类型是否为关闭或取消 */
			 if(InventoryApply.CLOSED.equals(inventoryApply.getStatus())||
				InventoryApply.CANCEL.equals(inventoryApply.getStatus())){
				 LocalizedMessage.addMessage("InventoryApplyDoc.createPickTicket.failed");
				 return;
			 }
			 /*创建发货单*/
			 PickTicket pickTicket = EntityFactory.getEntity(PickTicket.class);
			 
			 pickTicket.setCompany(inventoryApply.getCompany());//货主	
			 //设置单据类型
			 BillType billType = (BillType)this.commonDao.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
						new String[]{"companyId", "code"},new Object[]{inventoryApply.getCompany().getId(), PickTicket.SO_SWAP});
			 pickTicket.setCode(codeManager.getCodeByBillType(billType,WarehouseHolder.getWarehouse().getId()));//编号
			 pickTicket.setBillType(billType);
			 pickTicket.setStatus(PickTicketStatus.OPEN);
			 pickTicket.setWarehouse(WarehouseHolder.getWarehouse());
			 pickTicket.setOrderDate(new Date());
			 pickTicket.setInventoryApply(inventoryApply);
			 /* 设置收货人为受理仓库 */
			 
			 //根据受理仓库CODE查找组织列表中是否存在对应记录，没有则新建
			 
			 String code = inventoryApply.getApplyWarehouse().getCode();
			 
			 List organizations = commonDao.findByQuery("from Structure o where o.code = '"+code+"' and o.beCustomer = true and o.disabled = false");
			 Structure o ;
			 if(organizations.size()>0){
				 o = (Structure)organizations.get(0);
				 pickTicket.setCustomer(o);
				 pickTicket.setShipToName(o.getName());
				 pickTicket.setShipToAddress(o.getAddress());
				 pickTicket.setShipToContact(o.getContact());
			 }else{
				 throw new BusinessException("company.customer.undefine");
			 }
			 
			 //获取补货申请单明细
			 Set iads =  inventoryApply.getInventoryApplyDetails();
			 double sum = 0;
			 for(Object temp:iads){
				 InventoryApplyDetail iad = (InventoryApplyDetail)temp;
				 PickTicketDetail ptd = EntityFactory.getEntity(PickTicketDetail.class);
				 ptd.setPickTicket(pickTicket);
				 ptd.setItem(iad.getItem());
				 ptd.setNewLotInfo(iad.getNewLotInfo());
				 ptd.setPackageUnit(iad.getPackageUnit());
				 ptd.setOrderQuantity(iad.getPlanQuantity());
				 ptd.setOrderQtyOfMasterUnit(iad.getPlanQuantity() * iad.getPackageUnit().getConvertFigure());
				 
				 sum+=iad.getPlanQuantity();
				 
				 pickTicket.getPickTicketDetails().add(ptd);
			 }
			 
			 //设置发货单总数量
			 pickTicket.setOrderQuantity(sum);
			 
			 this.commonDao.store(pickTicket);
			 
			 //关闭申请单
			 inventoryApply.setStatus(InventoryApply.CLOSED);
		}
	}
	
	/**
	 * 取消补货申请单
	 */
	public void cancelApplyDoc(List<Long> ids){
		for(Long id:ids){
			 InventoryApply inventoryApply = this.commonDao.load(InventoryApply.class,id);
			 if(InventoryApply.APPLY.equals(inventoryApply.getStatus()))
				 inventoryApply.setStatus(InventoryApply.CANCEL);
		}
	}
	
	
	/**
	 * 自动创建库内补货单
	 * @param moveDocId  补货单ID
	 */
	@SuppressWarnings("unchecked")
	public void autoSupplyDoc() {
		/**
		 * 获取货品存放规则表中补货库位不为空的记录
		 */
		List<Structure> companys = this.commonDao.findByQuery("select distinct(rule.item.company) from ItemSupplyRule rule  WHERE rule.replenishmentLocation is not null and rule.warehouse.id = " + WarehouseHolder.getWarehouse().getId());
		for (Structure company : companys) {
			List supplyRules = commonDao.findByQuery("SELECT rule, (SELECT SUM(inv.qtyOfMasterPack) FROM Inventory inv " +
					"		WHERE inv.location.id = loc.id " +
					"		AND inv.itemKeyInventory.itemKey.item.id = item.id) AS itemQuantity " +
					" FROM ItemSupplyRule rule " +
					" LEFT JOIN rule.warehouse warehouse " +
					" LEFT JOIN rule.replenishmentLocation loc " +
					" LEFT JOIN rule.item.company company" +
					" LEFT JOIN rule.item item" +
					" WHERE warehouse.id = " + WarehouseHolder.getWarehouse().getId() + 
					" AND company.id = " + company.getId() + 
					" AND loc.countLock = '' AND loc.inLock = '' AND loc.outLock = '' " 
					);
			
			// 根据全局变量得到收货单的billTypeSOI属性，用于补货计划的分配
			BillType billType = (BillType) this.commonDao
					.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
							new String[] { "companyId", "code" },
							new Object[] {company.getId(), MoveDoc.MV_SUPPLY });
			
			// 如果货品存放规则中所有货品的补货库位都为空
			if (supplyRules.size() > 0) {
				createSupplyPlan(company, billType, supplyRules);
			} else {
				LocalizedMessage.addMessage("moveDoc.autoCreateMoveLp.noneed");
			}
		}
	}
	
	@SuppressWarnings("unchecked")
	private void createSupplyPlan(Structure company, BillType billType, List rules){
		Integer detailNumber = Integer.valueOf(GlobalParamUtils.getGloableStringValue("autoSupplyLocNumber"));
		List<Long> supplyLocs = this.commonDao.findByQuery("SELECT detail.dstLoc.id " +
				" FROM MoveDocDetail detail " +
				" WHERE detail.moveDoc.billType.id = " + billType.getId() +  
				" AND detail.moveDoc.status not in ('CLOSE', 'CANCEL')");
		/**
		 * 自动创建补货计划
		 */
		MoveDoc moveDoc = new MoveDoc();		
		moveDoc.setWarehouse(WarehouseHolder.getWarehouse());
		moveDoc.setStatus(MoveDocStatus.OPEN);
		moveDoc.setCreateDate(new Date());
		moveDoc.setUserTracking();
		moveDoc.setCompany(company);
		moveDoc.setCode(codeManager.getCodeByBillType(billType,WarehouseHolder.getWarehouse().getId()));
		// 设置单据类型
		moveDoc.setBillType(billType);
		moveDoc.setDetails(new HashSet<MoveDocDetail>());
		/**
		 * 自动创建补货明细
		 */
		Double quantity = 0.0;
		for (Object obj : rules) {
			Object[] ruleQty = (Object[]) obj;
			ItemSupplyRule itemRule = (ItemSupplyRule) ruleQty[0];
			Double inventory = (Double) ruleQty[1];
			if (inventory == null) {
				inventory = 0.0;
			}
			if (supplyLocs.contains(itemRule.getReplenishmentLocation().getId())) {
				//如果该规则对应货品已经在补货中，则跳过该货品
				continue;
			}
			
			// 得到具体商品的批次属性
			ItemKey itemKey = itemManager.getItemKey(new ItemKey("", itemRule.getItem(), new LotInfo(), null, null,null), Boolean.FALSE,null);
			// 如果库存数量小于补货下限，则根据算法计算出补货数量
			if (inventory <= itemRule.getMinReplenishment()) {
				quantity = itemRule.getReplenishmentQuantity()
						* Math.floor((itemRule.getMaxReplenishment() - inventory) / itemRule.getReplenishmentQuantity());
			} else {
				continue;
			}
			// 目标托盘设置为""
			// 库存状态设置为""
			// 包装单位取货品的基本单位：item.getMinPackageUnit()
			// 根据以上信息创建补货明细（补货计划、目标库位、目标托盘、货品批次、补货数量、包装单位、库存状态）
			this.generateMoveDocDetail(moveDoc, null, null, 
					itemRule.getReplenishmentLocation(), null, itemKey, 
					itemKey.getItem().getMinPackageUnit(), quantity,
					Inventory.STATUS_VALID, null, "");
			detailNumber --;
			
			if (detailNumber == 0) {
				break;
			}
		}
		// 检查补货单有无明细,如果无明细则提示无需补货
		if (moveDoc.getDetails().isEmpty()
				|| moveDoc.getDetails().size() < 1) {
			LocalizedMessage.addMessage("moveDoc.autoCreateMoveLp.noneed");
		} else {
			// 有明细则保存补货单并提示成功
			commonDao.store(moveDoc);
			LocalizedMessage.addMessage("moveDoc.autocreate.success");
		}
	}

	@SuppressWarnings("unchecked")
	public String getExpectedQuantityByTask(Map map) {
		Long taskId = (Long) map.get("task.id");
		Task task = this.commonDao.load(Task.class,taskId);
		Double muQty = task.getPlanQuantityMU() - task.getMovedQuantityMU();
		Double pkQty = 0D;
		if (task.getPackageUnit().getPrecision() == 0) {
			pkQty = Math.floor(muQty / task.getPackageUnit().getConvertFigure());
		} else {
			pkQty = DoubleUtils.formatByPrecision(muQty / task.getPackageUnit().getConvertFigure(), 
					task.getPackageUnit().getPrecision());
		}
		if (pkQty*task.getPackageUnit().getConvertFigure() < muQty) {
			return pkQty+task.getPackageUnit().getUnit()+"/"
				+(muQty - pkQty*task.getPackageUnit().getConvertFigure())
				+task.getItemKey().getItem().getMinPackageUnit().getUnit();
		} else {
			return pkQty+task.getPackageUnit().getUnit();
		}
	}
	
	public void removeInventoryApplyDetails(Long applyDocId, List<Long> applyDetailIds) {
		InventoryApply apply = commonDao.load(InventoryApply.class, applyDocId);
		if (apply.getStatus().equals(InventoryApply.INPUT) 
				|| apply.getStatus().equals(InventoryApply.APPLY)) {
			Set<InventoryApplyDetail> toBeRemoved = new HashSet<InventoryApplyDetail>();
			for (InventoryApplyDetail detail : apply.getInventoryApplyDetails()) {
				if (applyDetailIds.contains(detail.getId())) {
					apply.setQuantity(apply.getQuantity() - detail.getPlanQuantity());
					toBeRemoved.add(detail);
				}
			}
			apply.getInventoryApplyDetails().removeAll(toBeRemoved);
		}
	}
	
	public void addInventoryApplyDetail(Long applyDocId, InventoryApplyDetail detail) {
		InventoryApply apply = commonDao.load(InventoryApply.class, applyDocId);
		Item item = commonDao.load(Item.class, detail.getItem().getId());
	
		if (detail.getPlanQuantity() <= 0) {
			throw new BusinessException("docDetail.add.quantityError");
		}

		if (apply.getStatus().equals(InventoryApply.INPUT) 
				|| apply.getStatus().equals(InventoryApply.APPLY)) {
			PackageUnit packageUnit = commonDao.load(PackageUnit.class, detail.getPackageUnit().getId());
			if (!packageUnit.getItem().getId().equals(detail.getItem().getId())) {
				throw new BusinessException("docDetail.itemPackageUnit.disMatch");
			}

			// 新增明细
			if (detail.isNew()) {
				detail.setPackageUnit(packageUnit);
				detail.setItem(item);
				detail.setInventoryApply(apply);
				apply.getInventoryApplyDetails().add(detail);
				apply.setQuantity(apply.getQuantity()+ detail.getPlanQuantity());
			// 修改明细
			} else {
				double newQuantity = detail.getPlanQuantity();
				NewLotInfo newLotInfo= detail.getNewLotInfo();
				
				detail = commonDao.load(InventoryApplyDetail.class, detail.getId());
				double deltaQuantity = newQuantity - detail.getPlanQuantity();
				
				detail.setPlanQuantity(newQuantity);
				detail.setNewLotInfo(newLotInfo);
				apply.setQuantity(apply.getQuantity()+ deltaQuantity);
				if (detail.getPlanQuantity() == 0) {
					apply.getInventoryApplyDetails().remove(detail);
				}
			}
			commonDao.store(apply);
		}
	}
	public void manualMoveDetail(MoveDocDetail detail, Long packageUnitId, Double caseQty,Double puQty) {
		this.manualMoveDetail(detail, packageUnitId, caseQty, puQty,detail.getSrcLP());
	}
	public void manualMoveDetail(MoveDocDetail detail, Long packageUnitId, Double caseQty,Double puQty,Stock srcLp) {
		Location deslocation = this.commonDao.load(Location.class,detail.getDstLoc().getId());
		detail = this.commonDao.load(MoveDocDetail.class,detail.getId());
		PackageUnit packageUnit = commonDao.load(PackageUnit.class, packageUnitId);
		if (!(MoveDocStatus.CANCEL.equals(detail.getMoveDoc().getStatus()) 
				|| MoveDocStatus.CLOSE.equals(detail.getMoveDoc().getStatus())))  {
			Double moveQuantity=0d;
//			if(caseQty>0){
//				moveQuantity=caseQty*detail.getItem().getCAcoefficient()+puQty;
//			}else if(puQty>0){
				moveQuantity=puQty;
//			}
			moveQuantity=DoubleUtils.formatByPrecision(moveQuantity, packageUnit.getPrecision());
			Task t=putawayAllocator.manualAllocatebyLocation(detail, deslocation, packageUnit, moveQuantity,srcLp);
			Item i = this.load(Item.class, detail.getItem().getId());
			if(i.getBarcode()!=null) {
				t.setBarCode(i.getBarcode());//条码
				t.setWeight(i.getWeight());//重量
				t.setVolume(i.getVolume());//体积
			}
			this.moveTo(t, null);
		} else {
			throw new BusinessException("moveDoc.status.error");
		}
	}

	public void moveBatchInventory(List<Long> ids) {
		List<Inventory> inventories = this.commonDao.loadAll(Inventory.class,ids.toArray(new Long[] {}));
		Set<Structure> company = new HashSet<Structure>();
		for(Inventory inventory:inventories){
			
			company.add(inventory.getItemKeyInventory().getItemKey().getItem().getCompany());
		}
		Iterator<Structure> comIter = company.iterator();
		while(comIter.hasNext()){
			Structure org = comIter.next();
			MoveDoc moveDoc = EntityFactory.getEntity(MoveDoc.class);
			moveDoc.setWarehouse(WarehouseHolder.getWarehouse());
			moveDoc.setCreateDate(new Date());
			moveDoc.setStatus(MoveDocStatus.OPEN);
			BillType billType = (BillType)this.commonDao.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
					new String[]{"companyId","code"},
					new Object[]{org.getId(), MoveDoc.MV_MOVE});
			String code = codeManager.getCodeByBillType(billType,WarehouseHolder.getWarehouse().getId());	
			moveDoc.setCompany(org);
			moveDoc.setCode(code);
			moveDoc.setBillType(billType);
			for(Inventory inventory:inventories)
			{
				if(inventory.getItemKeyInventory().getItemKey().getItem().getCompany()==org){
					MoveDocDetail detail = EntityFactory.getEntity(MoveDocDetail.class);
					detail.setMoveDoc(moveDoc);
					detail.setItemKey(inventory.getItemKeyInventory().getItemKey());
					detail.setPackageUnit(inventory.getPackageUnit());
					detail.setSrcLoc(inventory.getLocation());
					detail.setSrcLP(inventory.getLP());
					detail.setDstLoc(null);
					detail.setDstLP(null);
					detail.setStorageDate(inventory.getStorageDate());
					detail.setSOI(inventory.getSOI());
					detail.setInventoryStatus(inventory.getStatus());
					if (moveDoc.getDetails() != null && moveDoc.getDetails().contains(detail)) {
						for (MoveDocDetail mdd : moveDoc.getDetails()) {
							if (mdd.equals(detail)) {
								mdd.add(inventory.getQtyOfMasterPack()-inventory.getQueuedQuantity());
								break;
							}
						}
					} else {
						detail.add(inventory.getQtyOfMasterPack()-inventory.getQueuedQuantity());
						moveDoc.getDetails().add(detail);
					}
				}
				
			}			
			if (moveDoc.getDetails().size() > 0) {
				moveDoc.setUserTracking();
				this.commonDao.store(moveDoc);	
			}
	
		}
		
	}
	
	public void deletePutAway(List<Long> ids) {
		for(Long id:ids){
			MoveDoc doc=this.commonDao.get(MoveDoc.class, id);
			if((doc.getStatus().equals(MoveDocStatus.OPEN)||doc.getStatus().equals(MoveDocStatus.CANCEL))&&doc.getAsnType()!=null){
				List<ReceivedRecord> rs=this.commonDao.findByQuery("from ReceivedRecord r where r.moveDocCode=:moveDocCode",
						new String[]{"moveDocCode"},new Object[]{doc.getCode()});
				for(ReceivedRecord r:rs){
					r.setMoveDocCode(null);
					this.commonDao.store(r);
					ASN asn=r.getAsn();
					if (!asn.getCompany().isBeAsnQuality() && !asn.getCompany().isBeRevLimit() && asn.isAllReceived()) {
						asn.setStatus(ASNStatus.RECEIVED);
					}else{
						asn.setStatus(ASNStatus.RECEIVING);
					}
				}
				this.commonDao.delete(doc);
			}
		}
	}
	
	public String getPlanQuantityByDetail(Map map) {
		Long moveDetailId = (Long) map.get("detail.id");
		if (moveDetailId == null) {
			return "0";
		}
		MoveDocDetail detail = commonDao.load(MoveDocDetail.class,
				moveDetailId);
		Item item=detail.getItem();
		PackageUnit packageUnit = commonDao.load(PackageUnit.class,detail.getPackageUnit().getId());
		double returnQty = 0;
		//取包装数量
		if (packageUnit.getPrecision() == 0) {
			//向上取整，得到整包装数量
			returnQty = Math.ceil(detail.getUnallocateQuantity()/detail.getPackageUnit().getConvertFigure());
		} else {
			//根据包装精度计算包装数量
			returnQty = DoubleUtils.formatByPrecision(detail.getUnallocateQuantity()/detail.getPackageUnit().getConvertFigure(), packageUnit.getPrecision());
		}
		String caseName=item.getCAname()==null?"箱":item.getCAname();
		if(item.getCAcoefficient()==0){
			return '0'+caseName+detail.getUnallocateQuantity()+packageUnit.getUnit();
		}else{
			int caseQty=(int) (detail.getUnallocateQuantity()/item.getCAcoefficient());
			int puQty=(int) (detail.getUnallocateQuantity()-caseQty*item.getCAcoefficient());
			return caseQty+caseName+puQty+packageUnit.getUnit()+"/"+returnQty+packageUnit.getUnit();
		}
	}
	
	public int getCaseQty(Map map) {
		Long moveDetailId = (Long) map.get("detail.id");
		if (moveDetailId == null) {
			return 0;
		}
		MoveDocDetail detail = commonDao.load(MoveDocDetail.class,
				moveDetailId);
		Item item=detail.getItem();
		if(item.getCAname()==null||item.getCAname().equals("")||item.getCAcoefficient()==null||item.getCAcoefficient()==0){
			return 0;
		}else{
			int caseQty=(int) (detail.getUnallocateQuantity()/item.getCAcoefficient());
			return caseQty;
		}
	}
	
	public int getPuQty(Map map) {
		Long moveDetailId = (Long) map.get("detail.id");
		if (moveDetailId == null) {
			return 0;
		}
		MoveDocDetail detail = commonDao.load(MoveDocDetail.class,moveDetailId);
		Item item=detail.getItem();
		if(item.getCAname()==null||item.getCAname().equals("")||item.getCAcoefficient()==null||item.getCAcoefficient()==0){
			return (int)detail.getUnallocateQuantity();
		}else{
			int caseQty=(int) (detail.getUnallocateQuantity()/item.getCAcoefficient());
			return (int)(detail.getUnallocateQuantity()-caseQty*item.getCAcoefficient());
		}
	}
	
	public int getsjQty(Map map) {
		double sjcounts=0;//上架数量
		Long moveDetailId = (Long) map.get("detail.id");
		Long moveDocId = (Long) map.get("detail.moveDoc.id");
		if (moveDetailId == null) {
			return 0;
		}
		MoveDocDetail detail = commonDao.load(MoveDocDetail.class,
				moveDetailId);
		if(detail.getSrcLPCode()!=null &&!detail.getSrcLPCode().equals("")) {
			List<MoveDocDetail> moveDocDetails=commonDao.findByQuery(" from MoveDocDetail mdd where mdd.moveDoc.id=:id and mdd.srcLPCode=:srcLPCode and (mdd.planQuantityOfMU-mdd.allocateQuantity)> 0",
					new String[] { "id","srcLPCode"},new Object[] {moveDocId,detail.getSrcLPCode()});
			for(MoveDocDetail details :moveDocDetails) {
				 sjcounts+=details.getPlanQuantityOfMU();
			}
			
		}
		return (int)sjcounts;
	}

	@Override
	public void putawayConfirm(MoveDocDetail detail, Long dstLocId,Long moveDocId) {
		List<MoveDocDetail> moveDocDetails=commonDao.findByQuery(" from MoveDocDetail mdd where mdd.moveDoc.id=:id and mdd.srcLPCode=:srcLPCode and (mdd.planQuantityOfMU-mdd.allocateQuantity)> 0",
				new String[] { "id","srcLPCode"},new Object[] {moveDocId,detail.getSrcLPCode()});
		for(MoveDocDetail details:moveDocDetails) {
			/*ItemKey itemKey=this.load(ItemKey.class, details.getItemKey().getId());
			List<Item> items=commonDao.findByQuery(" from Item i where i.id=:id ",
					new String[] { "id"},new Object[] {itemKey.getItem().getId()});
			if(items.size()>0) {
				item=items.get(0);
				if(item.getCAcoefficient()==null||item.getCAcoefficient()==0) {
					caseQty=0d;
				}else {
					 caseQty=(details.getUnallocateQuantity()/item.getCAcoefficient());
				}
			}
			if(item.getCAcoefficient()==null||item.getCAcoefficient()==0){
				puQty=details.getUnallocateQuantity();
			}else{
				 caseQty=(details.getUnallocateQuantity()/item.getCAcoefficient());
				 puQty=(details.getUnallocateQuantity()-caseQty*item.getCAcoefficient());
			}*/
			/*PackageUnit packageUnit=this.load(PackageUnit.class, details.getPackageUnit().getId());
			ItemKey itemKey=this.load(ItemKey.class, details.getItemKey().getId());
			List<Item> items=commonDao.findByQuery(" from Item i where i.id=:id ",
					new String[] { "id"},new Object[] {itemKey.getItem().getId()});
			if(items.size()>0) {
				item=items.get(0);
				if(item.getCAcoefficient()==null||item.getCAcoefficient()==0) {
					caseQty=0d;
				}else {
					 caseQty=(details.getUnallocateQuantity()/item.getCAcoefficient());
				}
			}
			if(item.getCAcoefficient()==null||item.getCAcoefficient()==0){
				puQty=details.getUnallocateQuantity();
			}else{
				 caseQty=(details.getUnallocateQuantity()/item.getCAcoefficient());
				 puQty=(details.getUnallocateQuantity()-caseQty*item.getCAcoefficient());
			}*/
			Location dstloc=this.load(Location.class, dstLocId);//目标库位
			details.setDstLoc(dstloc);
			manualMoveDetail(details,details.getPackageUnit().getId(),0d,(details.getUnallocateQuantity()),details.getSrcLP());
		}
	
	}
	
	@Override
	public void manualMoveDetail(Long moveDocId, Map locs) {
		Iterator it = locs.entrySet().iterator();
		while(it.hasNext()) {
		 	Map.Entry entry = (Map.Entry) it.next();	
			Long dId=(Long) entry.getKey();
			MoveDocDetail d=this.commonDao.get(MoveDocDetail.class, dId);
			List value=  (List) entry.getValue();
			String locationCode = String.valueOf(value.get(0));
			if(locationCode!=null&&!locationCode.equals("-")){
				locationCode=locationCode.toUpperCase();
				if(locationCode.substring(0, 1).equals("-")){
					locationCode=locationCode.substring(1,locationCode.length());
				}
				List<Location> ls=this.commonDao.findByQuery("from Location l where upper(l.code)='"+locationCode+"'");
				if(ls.size()>0){
					d.setDstLoc(ls.get(0));
					manualMoveDetail(d, d.getPackageUnit().getId(), 0d, d.getUnallocateQuantity(),d.getSrcLP());
				}else{
					throw new BusinessException(locationCode+"库位不存在");
				}
			}
			
		}
		
	}
	public void storeLabel(Label l){
		if(l.isNew()){
			l.setWarehouse(WarehouseHolder.getWarehouse());
			l.setCreateDate(new Date());
			l.setStatus(MoveDocStatus.OPEN);
		}
		commonDao.store(l);
	}
	
	public void deleteLabel(List<Long> ids) {
		for(Long id:ids){
			Label l=commonDao.load(Label.class, id);
			List<LabelDetail> lds=this.commonDao.findByQuery("from LabelDetail l where l.label.id="+id);
			for(LabelDetail ld :lds){
				commonDao.delete(ld);
			}
			commonDao.delete(l);
		}
	}
	
	public void addLabelDetails(Long LabelId, Map invs) {
		Iterator it = invs.entrySet().iterator();
		Label l=commonDao.load(Label.class, LabelId);
		while(it.hasNext()) {
		 	Map.Entry entry = (Map.Entry) it.next();	
			Long inventoryId=(Long) entry.getKey();
			List value=  (List) entry.getValue();
			Inventory inventory = commonDao.load(Inventory.class, inventoryId);
			String qty = String.valueOf(value.get(0));
					LabelDetail detail = EntityFactory.getEntity(LabelDetail.class);
					// 设置商品属性
					detail.setItemKey(inventory.getItemKeyInventory().getItemKey());
					// 设置包装单位
					detail.setPackageUnit(inventory.getPackageUnit());
					detail.setSrcLoc(inventory.getLocation());
					detail.setDstLoc(inventory.getLocation());
					detail.setLabel(l);
					detail.setInventoryStatus(inventory.getStatus());
					detail.setStorageDate(inventory.getStorageDate());
					detail.setSOI(inventory.getSOI());
					detail.setPlanQuantity(Double.parseDouble(qty));
					detail.setInventoryid(inventory.getId());				
					commonDao.store(detail);
//				putawayAllocator.allocate(moveDocId);
		}
		List<Double> lds=this.commonDao.findByQuery("select nvl(sum(l.planQuantity),0) from LabelDetail l where l.label.id="+LabelId);
		if(lds.size()>0){
		l.setQuantity(lds.get(0));
		commonDao.store(l);
		}
	}
	
	public void inactiveLabel(List<Long> ids){
		
		for(Long id:ids){
			Label l=commonDao.load(Label.class, id);
			List<LabelDetail> lds=this.commonDao.findByQuery("from LabelDetail l where l.label.id="+id);
			for(LabelDetail ld :lds){
				
				Inventory inventory = commonDao.load(Inventory.class, ld.getInventoryid());
				if(inventory!=null){
					if((inventory.getQtyOfMasterPack()-inventory.getQueuedQuantity())==ld.getPlanQuantity()){
						inventory.setLabeling(true);;
					}else{
						
						
						
						
						
					}
					commonDao.store(inventory);
					
				}
				
			}
			commonDao.delete(l);
		}
		
	}

	// 删除回单影像
	@Override
	public void deleteSignFile(List<Long> ids) {
		for (Long id : ids) {
			SignFile signFile = this.get(SignFile.class, id);
			Inventory inventory = signFile.getInventory();
			if (signFile != null) {
				commonDao.delete(signFile);
			} else {
				throw new BusinessException("待删除文件不存在！");
			}
			inventory.removeFiles(signFile);// 移除关联
			// 删除对应的图片资料
			String fileUrl = GlobalParamUtils
					.getGloableStringValue("imageTarget")
					+ signFile.getFileName();
			File file = new File(fileUrl);
			file.delete();
			commonDao.store(inventory);
		}
	}
	@Override
	public void addMoveTransDetails(Long moveObjectId, Map invs) {
		Iterator it = invs.entrySet().iterator();
		while(it.hasNext()) {
		 	Map.Entry entry = (Map.Entry) it.next();	
			Long invId=(Long) entry.getKey();
			List value=  (List) entry.getValue();
			String qty = String.valueOf(value.get(0));
			double move_qty=Double.parseDouble(qty);
			MoveObject obj=this.commonDao.get(MoveObject.class, moveObjectId);
			Inventory inv=this.commonDao.get(Inventory.class, invId);
			if(move_qty<=inv.getAvaliableQuantity()){
				MoveObjectDetail d=generateMoveObjecrDetail(obj,invId, move_qty);
				inv.setQueuedQuantity(inv.getQueuedQuantity()+move_qty);
				this.commonDao.store(inv);
			}else{
				throw new BusinessException("转移数量不能大于可用数量");
			}
		}
		refreshMoveTransQty(moveObjectId);
	}
	
	public void refreshMoveTransQty(Long moveObjectId){
		String hql="select nvl(sum(d.planQuantity),0) from MoveObjectDetail d where d.moveObject.id=:docId";
		double qty=(Double)commonDao.findByQuery(hql,new String[]{"docId"},new Object[]{moveObjectId}).get(0);
		MoveObject obj=this.commonDao.get(MoveObject.class, moveObjectId);
		obj.setOrderQuantity(qty);
		this.commonDao.store(obj);
	}
	private MoveObjectDetail generateMoveObjecrDetail(MoveObject moveObject,Long invId, double quantity) {
		Inventory inv=this.commonDao.get(Inventory.class, invId);
		MoveObjectDetail detail = EntityFactory.getEntity(MoveObjectDetail.class);
		// 设置商品属性
		detail.setItemKey(inv.getItemKeyInventory().getItemKey());
		// 设置包装单位
		detail.setPackageUnit(inv.getPackageUnit());
		detail.setSrcLoc(inv.getLocation());
		detail.setSrcLP(inv.getLP());
		detail.setSrcLPCode(inv.getLP()==null?null:inv.getLP().getLP());
		detail.setDstLoc(inv.getLocation());
		detail.setDstLP(inv.getLP());
		detail.setDstLPCode(inv.getLP()==null?null:inv.getLP().getLP());
		detail.setMoveObject(moveObject);
		detail.setInventoryStatus(inv.getStatus());
		detail.setStorageDate(inv.getStorageDate());
		detail.setSOI(inv.getSOI());
		detail.add(quantity);
		moveObject.getDetails().add(detail);
		detail.setLineNo(moveObject.getDetails().size());
		detail.setInvId(inv.getId());
		return detail;
	}
	
	public void deleteMoveTransDetails(Long moveObjectId, List<Long> moveObjectDetailIds) {
		MoveObject moveObject = commonDao.load(MoveObject.class, moveObjectId);
		if (MoveDocStatus.OPEN.equals(moveObject.getStatus())||MoveDocStatus.ALLOCATE.equals(moveObject.getStatus())) {
			for (Long id : moveObjectDetailIds) {
				MoveObjectDetail detail = commonDao.load(MoveObjectDetail.class, id);
				Inventory inv =this.commonDao.get(Inventory.class, detail.getInvId());
				inv.setQueuedQuantity(inv.getQueuedQuantity()-detail.getOrderQuantity());
//				moveObject.removeDetail(detail);
				this.commonDao.delete(detail);
			}
			commonDao.store(moveObject);
			refreshMoveTransQty(moveObjectId);
		}
	}
	/**
	 * 保存新增的移位计划
	 */
	public void storeMoveTrans(MoveObject moveObject) {		
		//根据全局变量得到收货单的billTypeSOI属性，用于上架计划的分配 zongxing.zeng
		if (moveObject.isNew()) {
			moveObject.setCode(this.codeManager.getCodeForYm("MT",5));
			moveObject.setWarehouse(WarehouseHolder.getWarehouse());
			moveObject.setStatus(MoveDocStatus.OPEN);
			moveObject.setUserTracking();
			moveObject.setMoveType("货权转移");
		}
		this.commonDao.store(moveObject);
	}
	
	@SuppressWarnings("unchecked")
	public void deleteMoveTrans(List<Long> moveObjectIds) {
		String errMsg = "";
		for (Long moveDocId : moveObjectIds) {
			MoveObject moveDoc = commonDao.load(MoveObject.class, moveDocId);
			if (MoveDocStatus.OPEN.equals(moveDoc.getStatus())){
				List<Long> ids=this.commonDao.findByQuery("select id from MoveObjectDetail d where d.moveObject.id="+moveDocId);
				if(ids.size()>0){
					this.deleteMoveTransDetails(moveDocId, ids);
				}
				this.commonDao.delete(moveDoc);
				errMsg+=moveDoc.getCode()+" 单据删除成功;";
			}
			else
				errMsg+=moveDoc.getCode()+" 单据删除失败;";
		}
		LocalizedMessage.addLocalizedMessage(errMsg);
		
	}
}
