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

import java.io.IOException;
import java.io.ObjectInputStream;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import com.dev.swms.server.interfaces.ItemJobLauncher;
import com.dev.swms.server.model.base.BillType;
import com.dev.swms.server.model.base.CompanyCode;
import com.dev.swms.server.model.base.Line;
import com.dev.swms.server.model.base.Pilot;
import com.dev.swms.server.model.base.Structure;
import com.dev.swms.server.model.base.TransSite;
import com.dev.swms.server.model.base.Transportation;
import com.dev.swms.server.model.base.Worker;
import com.dev.swms.server.model.inventory.InventoryApply;
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.ASNDetail;
import com.dev.swms.server.model.receiving.ASNStatus;
import com.dev.swms.server.model.shipping.BOL;
import com.dev.swms.server.model.shipping.BOLCaseDetail;
import com.dev.swms.server.model.shipping.BOLDetail;
import com.dev.swms.server.model.shipping.BOLDetailLog;
import com.dev.swms.server.model.shipping.BOLStatus;
import com.dev.swms.server.model.shipping.MasterBOL;
import com.dev.swms.server.model.shipping.MasterBOLStatus;
import com.dev.swms.server.model.shipping.Package;
import com.dev.swms.server.model.shipping.PackageDetail;
import com.dev.swms.server.model.shipping.PickTicket;
import com.dev.swms.server.model.shipping.PickTicketDetail;
import com.dev.swms.server.model.shipping.PickTicketStatus;
import com.dev.swms.server.model.shipping.PreAllocate;
import com.dev.swms.server.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.MasterBolManager;
import com.dev.swms.server.service.sequence.BussinessCodeManager;
import com.dev.swms.server.utils.DateUtil;
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;
import com.dev.energy.server.web.security.UserHolder;

@SuppressWarnings("unchecked")
public class DefaultMasterBolManager extends DefaultBaseManager implements MasterBolManager {
	
	protected final InventoryManager inventoryManager;
	protected final BussinessCodeManager bussinessCodeManager;
	protected final ItemManager itemManager;
	protected final InterfaceLogManager logManager;
	private String url;
	private String ruleName;
	private String defaultCarrierCode;
	
	public void setDefaultCarrierCode(String defaultCarrierCode) {
		this.defaultCarrierCode = defaultCarrierCode;
	}
	
	public void setRuleName(String ruleName) {
		this.ruleName = ruleName;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public DefaultMasterBolManager(InventoryManager manager,
			 BussinessCodeManager manager3, 
			ItemManager manager4, InterfaceLogManager manager5) {
		this.inventoryManager = manager;
		this.bussinessCodeManager = manager3;
		this.itemManager = manager4;
		this.logManager = manager5;
	}

	public MasterBOL getMasterBolByCode(String code) {
		List result = commonDao.findByNamedQuery("getMasterBolByCode",
				new String[] { "code"}, 
				new String[] { code });
		if (result.size() >= 1) {
			return (MasterBOL) result.get(0);
		}
		return null;
	}

	public void multiShipConfirm(List<Long> ids) {
		for(Long id:ids){
			MasterBOL masterBOL = commonDao.load(MasterBOL.class,id);
			if (MasterBOLStatus.OPEN.equals(masterBOL.getStatus())||MasterBOLStatus.PICK_ALL.equals(masterBOL.getStatus())||MasterBOLStatus.PICKUP.equals(masterBOL.getStatus())) {
				List<PickTicket> pts=this.commonDao.findByQuery("from PickTicket p where p.masterBOL.id=:masterBOLId",
						new String[]{"masterBOLId"},new Object[]{id});
				
				for (PickTicket pt : pts) {
					if(pt.getPickedQuantity()<pt.getOrderQuantity()){
						throw new BusinessException("还有未拣货完成的订单，不能发运");
					}
				}
				for (PickTicket pt : pts) {
					pickShip(pt, null);
				}
				masterBOL.setLeaveTime(new Date());
				masterBOL.setStatus(MasterBOLStatus.SHIP_ALL);
				commonDao.store(masterBOL);
				refreshMasterBOL(masterBOL.getId());
			}
		}
		
	}

	
	/**
	 * 功能描述：删除BOL
	 * 作者：yufei.ge
	 * 步骤：
	 * 1.将TaskLog的加入BOL数量置为0
	 * 2.扣减PickTicket及PickTicket_Detail加入BOL数量
	 * 3.删除BOL以及对应的包装信息     
	 * */
	
	@SuppressWarnings("unchecked")
	public void bolDelete(List<Long> BOLIds) {
		for(Long BOLId:BOLIds){
			//获得BOL
			BOL bol = this.commonDao.load(BOL.class, BOLId);
			
//			根据BOL获得pickTicket
			PickTicket pickTicket = bol.getPickTicket();
			if(!StringUtils.isEmpty(pickTicket.getWaveCode())){
				deleteBOLCaseDetail(bol);//删除BOL对应的笼车
			}
			
			if(null != bol.getMasterBOL()){
				throw new BusinessException("bol.masterBol.isNotNull");
			}
			//根据pickTicket获取所有task_log
			List<TaskLog> taskLogs = commonDao.findByNamedQuery("findTaskLogByPickTicket",
					new String[]{"pickTicket"}, 
					new Object[]{pickTicket});
			
			double deltaQty = 0;
			//在包装明细里匹配对应的tasklog
			for(BOLDetail packageDetail : bol.getBOLDetails()){
				
				//要扣除的数量
				double pkgQtyMU = packageDetail.getBolQuantity() * packageDetail.getPackageUnit().getConvertFigure();
				
				// 在tasklog里寻找匹配数据扣减数量
				for(TaskLog taskLog : taskLogs){
					if(taskLog.getPackageUnit().equals(packageDetail.getPackageUnit()) && taskLog.getItemKey().equals(packageDetail.getItemKey())){
						//获取当前task_log对应的pickTicketDetail，以便扣减其数量
						PickTicketDetail pickTicketDetail = taskLog.getTask().getPickTicketDetail();
						double logQtyMU = taskLog.getBolQuantity()*taskLog.getPackageUnit().getConvertFigure();
						
						//当前tasklog的BOL数量>=要扣减的BOL数量时,直接设置BOL数量=BOL数量-要扣减的BOL数量
						if(logQtyMU >= pkgQtyMU){
							taskLog.setBolQuantity(taskLog.getBolQuantity() - (pkgQtyMU/taskLog.getPackageUnit().getConvertFigure()));
							pickTicketDetail.setBOLQuantity(pickTicketDetail.getBOLQuantity() - pkgQtyMU);
							pickTicketDetail.setPackageQuantity(pickTicketDetail.getPackageQuantity() - pkgQtyMU);
							deltaQty += pkgQtyMU;
							pkgQtyMU = 0;
						} else {
							pkgQtyMU -= logQtyMU;
							pickTicketDetail.setBOLQuantity(pickTicketDetail.getBOLQuantity() - logQtyMU);
							pickTicketDetail.setPackageQuantity(pickTicketDetail.getPackageQuantity() - logQtyMU);
							taskLog.setBolQuantity(0);
							deltaQty += logQtyMU;
						}
						this.commonDao.store(pickTicketDetail);
					}
					if (pkgQtyMU == 0) {
						break;
					}
				}
			}
			
			//设置pickTicket的BOL数量
			pickTicket.setBOLQuantity(pickTicket.getBOLQuantity() - deltaQty);
			pickTicket.setPackageQuantity(pickTicket.getPackageQuantity() - deltaQty);
			this.commonDao.store(pickTicket);
			//删除BOL
			commonDao.delete(bol);
		}
		
	}
	
	private void deleteBOLCaseDetail(BOL bol) {
		String hql = "select task from Task task inner join task.waveDocDetail waveDocDetail inner join waveDocDetail.pickTicket pickTicket "
				+ " where pickTicket.id=" + bol.getPickTicket().getId();
		List<Task> tasks = this.commonDao.findByQuery(hql);
		for (Task task : tasks) {
			if(task.getCageInfo().isHasBOL()){
				task.getCageInfo().setHasBOL(false);
				this.commonDao.store(task.getCageInfo());
			}
		}
		
		this.commonDao.executeByNamed("deleteBOLCaseDetailByBOL",new String[]{"bolId"},new Object[]{bol.getId()});
		this.commonDao.load(BOLCaseDetail.class,new Long(0));
	}

	public void bolShip(List<Long> BOLIds, Long workerId) {
		String errMsg = "";
		for (Long BOLId:BOLIds) {
			BOL BOL = this.commonDao.load(BOL.class, BOLId);
			if (BOL.getMasterBOL() == null && BOLStatus.OPEN.equals(BOL.getStatus()) && BOL.getCarrier() != null) {
				bolShip(BOL,workerId);
				errMsg+=BOL.getCode()+" 发运成功;";
			}
			else
				errMsg+=BOL.getCode()+" 发运失败;";
		}
		
		LocalizedMessage.addLocalizedMessage(errMsg);
	}
	
	public void createASNIfNecessary(BOL bol) {
		InventoryApply inventoryApply = bol.getPickTicket().getInventoryApply();
		
		//如果不是库间调拨发货单或调拨申请的原仓库为当前仓库，则不创建ASN
		if (inventoryApply == null || inventoryApply.getApplyWarehouse().equals(WarehouseHolder.getWarehouse())) {
			return;
		}

		BillType asnSwarp = (BillType) commonDao.findByNamedQueryUniqueResult("getBillTypeByCompanyAndCode",
				new String[] {"companyId", "code"}, 
				new Object[] {inventoryApply.getCompany().getId(), ASN.PO_SWAP});
		
		if (asnSwarp == null) {
			return;
		}
		
		//自动生成目标仓库收货单
		ASN newASN = EntityFactory.getEntity(ASN.class);
		String code = bussinessCodeManager.getCodeByBillType(asnSwarp, inventoryApply.getApplyWarehouse().getId());
		newASN.setCode(code);
		newASN.setWarehouse(inventoryApply.getApplyWarehouse());
		newASN.setCompany(inventoryApply.getCompany());
		newASN.setBillType(asnSwarp);
		newASN.setFromAddress(inventoryApply.getAcceptWarehouse().getAddress());
		newASN.setFromContact(inventoryApply.getAcceptWarehouse().getContact());
		newASN.setFromName(inventoryApply.getAcceptWarehouse().getName());
		newASN.setOrderDate(new Date());
		newASN.setRelatedBill1(bol.getMasterBOL() != null ? bol.getMasterBOL().getCode() : bol.getCode());
		newASN.setRelatedBill2(bol.getPickTicket().getCode());
		newASN.setStatus(ASNStatus.ACTIVE);
		newASN.setUserTracking();
		newASN.setVehicle(bol.getMasterBOL() != null ? bol.getMasterBOL().getTrailer() : bol.getTrailer());
		newASN.setAsnDetails(new HashSet<ASNDetail>());
		//对收货单增加明细
		addASNDetails(bol, newASN);
		commonDao.store(newASN);
	}
	
	/**
	 * 增加发货单明细
	 * @param bol
	 * @param newASN
	 */
	public void addASNDetails(BOL bol, ASN newASN) {
		for(BOLDetail detail : bol.getBOLDetails()){
			ASNDetail asnDetail = new ASNDetail();
			asnDetail.setAsn(newASN);
			asnDetail.setItem(detail.getItemKey().getItem());
			asnDetail.setLotInfo(detail.getItemKey().getLotInfo());
			asnDetail.setPackageUnit(detail.getPackageUnit());
			asnDetail.setExpectedQuantity(detail.getShipQuantity());
			asnDetail.setExpectedQtyOfMasterUnit(detail.getShipQuantity()*detail.getPackageUnit().getConvertFigure());
			asnDetail.setReceivedQuantity(.0);
			asnDetail.setPO("");
			asnDetail.setDock(null);
			newASN.addASNDetail(asnDetail);
		}
	}
	
	@SuppressWarnings("unchecked")
	private void bolShip(BOL bol, Long workerId) {
		Worker worker = null;
		if (workerId != null) {
			worker = this.load(Worker.class, workerId);
			bol.setWorker(worker);
		}
		//发运确认时回写bolDetail的shipedQuantity
		for(BOLDetail detail : bol.getBOLDetails()){
			detail.setShipQuantity(detail.getBolQuantity());
		}
		for (Package pkg : bol.getPackages()) {
			for (PackageDetail pkDetail : pkg.getDetails()) {
				List<TaskLog> taskLogs = commonDao.findByQuery("FROM TaskLog log WHERE log.bolQuantity>log.shipQuantity and log.task.pickTicketDetail.pickTicket.id = " + bol.getPickTicket().getId());
				double shipQuantity = .0;
				for (TaskLog log : taskLogs) {
					if (log.getItemKey().equals(pkDetail.getItemKey()) 
							&& log.getPackageUnit().equals(pkDetail.getPackageUnit())) {
						double quantity = (pkDetail.getQuantity()*pkg.getQuantity() - shipQuantity) < (log.getBolQuantity()-log.getShipQuantity())
							? (pkDetail.getQuantity()*pkg.getQuantity() - shipQuantity) 
							: (log.getBolQuantity()-log.getShipQuantity());
						log.setShipQuantity(quantity);
						PickTicketDetail dtl = log.getTask().getPickTicketDetail();
			 			//扣减发货单及其明细BOL数量、包箱数量，增加发货单及其明细的发运数量
			        	dtl.ship(quantity*log.getPackageUnit().getConvertFigure());
						//扣减库存
						inventoryManager.ship(bol.getPickTicket().getDock().getId(),
								log.getItemKey(),
								quantity,
								log.getPackageUnit().getId(),
								null, 
								log.getInventoryStatus(),
								log.getStorageDate(),
								log.getSOI(),
								bol.getPickTicket().getCode(),
								bol.getPickTicket().getBillType());
						shipQuantity += quantity;
						if(shipQuantity == (pkDetail.getQuantity()*pkg.getQuantity())) {
							break;
						}
					}
				}
			}
		}
		//扣减预分配表中的数量
		updatePreAllocate(bol);
		//修改BOL状态
		bol.setShipDate(new Date());
		bol.setStatus(BOLStatus.SHIP_ALL);
		bol.setUserTracking();
		//自动创建发货单
		createASNIfNecessary(bol);
		//调用接口发送发货确认消息
		//logManager.bolShipResponse(bol);
	}
	
	@SuppressWarnings("unchecked")
	private void pickShip(PickTicket pt, Long workerId) {
		Worker worker = null;
		if (workerId != null) {
			worker = this.load(Worker.class, workerId);
		}
		List<TaskLog> taskLogs = commonDao.findByQuery("FROM TaskLog log WHERE log.movedQuantity>log.shipQuantity and log.task.pickTicketDetail.pickTicket.id = " + pt.getId());
		for (TaskLog log : taskLogs) {
			double shipQuantity = log.getMovedQuantity()-log.getShipQuantity();
			log.setShipQuantity(shipQuantity);
			PickTicketDetail detail = log.getTask().getPickTicketDetail();
			 //扣减发货单及其明细BOL数量、包箱数量，增加发货单及其明细的发运数量
			detail.ship(shipQuantity*log.getPackageUnit().getConvertFigure());
			//扣减库存
			inventoryManager.ship(pt.getDock().getId(),
					log.getItemKey(),
					shipQuantity,
					log.getPackageUnit().getId(),
					null, 
					log.getInventoryStatus(),
					log.getStorageDate(),
					log.getSOI(),
					pt.getCode(),
					pt.getBillType());
			detail.setStorageDate(log.getStorageDate());
		}
		updatePreAllocate(pt.getId());
		updatePickTicketQuantity(pt.getId());
		if(pt.getShipDate()==null){
			pt.setShipDate(new Date());
		}
		pt.setStatus(BOLStatus.SHIP_ALL);
		pt.setUserTracking();
		//自动创建发货单
		//createASNIfNecessary(bol);
		//调用接口发送发货确认消息
		//logManager.bolShipResponse(bol);
	}
	
	
	/**
	 * 扣减预分配表中的数量
	 * @param bol
	 */
	@SuppressWarnings("unchecked")
	public void updatePreAllocate(BOL bol) {
		//扣减预分配表流程调整
		//1、根据BOLDetail中itemKey依次扣减PreAllocate
		//2、如果PreAllocate中记录的数量被扣减完毕，则直接删除PreAllocate记录
		//3、根据BOLDetail中item依次扣减PreAllocate
		//4、如果PreAllocate中记录的数量被扣减完毕，则直接删除PreAllocate记录
		List<PreAllocate> preAllocates = commonDao.findByNamedQuery("getPreAllocateByCondition", 
				new String[]{"code", "warehouseId"}, 
				new Object[]{bol.getPickTicket().getCode(), WarehouseHolder.getWarehouse().getId()});

		Map<BOLDetail, Double> details = new HashMap<BOLDetail, Double>();
		for (BOLDetail detail : bol.getBOLDetails()) {
			if (details == null || !details.containsKey(detail)) {
				details.put(detail, detail.getShipQuantity()*detail.getPackageUnit().getConvertFigure());
			} else {
				double qty = details.get(detail);
				qty += detail.getShipQuantity()*detail.getPackageUnit().getConvertFigure();
				details.put(detail, qty);
			}
		}
		List<PreAllocate> toBeRemoved = new ArrayList<PreAllocate>();
		
		//第一次循环
		for (BOLDetail dtl : details.keySet()) {
			for (PreAllocate preAllocate : preAllocates) {
				if (preAllocate.getItem().equals(dtl.getItemKey().getItem())
						&& ((preAllocate.getLot()==null && dtl.getItemKey().getLot()==null) 
						|| (preAllocate.getLot().equals(dtl.getItemKey().getLot())))) {
					if (details.get(dtl) > preAllocate.getPreAllocatedQuantity()) {
						details.put(dtl, details.get(dtl) - preAllocate.getPreAllocatedQuantity());
						toBeRemoved.add(preAllocate);
					} else {
						preAllocate.setPreAllocatedQuantity(preAllocate.getPreAllocatedQuantity() - details.get(dtl));
						if (preAllocate.getPreAllocatedQuantity() == 0) {
							toBeRemoved.add(preAllocate);
						}
						details.put(dtl, 0.0);
					}
				}
			}
		}
		commonDao.deleteAll(toBeRemoved);
		toBeRemoved.clear();
		
		
		//第二次循环
		for (BOLDetail dtl : details.keySet()) {
			if (details.get(dtl) <= 0) {
				continue;
			}
			for (PreAllocate preAllocate : preAllocates) {
				if (preAllocate.getItem().equals(dtl.getItemKey().getItem())) {
					if (details.get(dtl) > preAllocate.getPreAllocatedQuantity()) {
						details.put(dtl, details.get(dtl) - preAllocate.getPreAllocatedQuantity());
						toBeRemoved.add(preAllocate);
					} else {
						preAllocate.setPreAllocatedQuantity(preAllocate.getPreAllocatedQuantity() - details.get(dtl));
						if (preAllocate.getPreAllocatedQuantity() == 0) {
							toBeRemoved.add(preAllocate);
						}
						details.put(dtl, 0.0);
					}
				}
			}
		}
		commonDao.deleteAll(toBeRemoved);
	}
	
	public void storeMasterBOL(MasterBOL masterBOL) {
		if (masterBOL.isNew()) {
			masterBOL.setWarehouse(WarehouseHolder.getWarehouse());
			masterBOL.setStatus(MasterBOLStatus.OPEN);
			masterBOL.setUserTracking();
			masterBOL.setCode(bussinessCodeManager.getCodeForYm("MB", 4));
			this.store(masterBOL);
		} else {
			Line line=null;
			MasterBOL dbMB = commonDao.load(MasterBOL.class, masterBOL.getId());
			if(dbMB.getLine()!=null) {
				 line =this.load(Line.class, masterBOL.getLine().getId());
			}
			
			if (masterBOL.getCarrier() != null && masterBOL.getCarrier().getId() != 0) {
				dbMB.setCarrier(commonDao.load(Structure.class, masterBOL.getCarrier().getId()));
			} else {
				dbMB.setCarrier(null);
			}
			if (masterBOL.getStartPosition() != null && masterBOL.getStartPosition().getId() != 0) {
				dbMB.setStartPosition(commonDao.load(TransSite.class, masterBOL.getStartPosition().getId()));
			} else {
				dbMB.setStartPosition(null);
			}
			if (masterBOL.getAimPosition() != null && masterBOL.getAimPosition().getId() != 0) {
				dbMB.setAimPosition(commonDao.load(TransSite.class, masterBOL.getAimPosition().getId()));
			} else {
				dbMB.setAimPosition(null);
			}

			if (masterBOL.getTransportation() != null && masterBOL.getTransportation().getId() != 0) {
				dbMB.setTransportation(commonDao.load(Transportation.class, masterBOL.getTransportation().getId()));
			} else {
				dbMB.setTransportation(null);
			}
			if (masterBOL.getPilot() != null && masterBOL.getPilot().getId() != 0) {
				dbMB.setPilot(commonDao.load(Pilot.class, masterBOL.getPilot().getId()));
			} else {
				dbMB.setPilot(null);
			}
			dbMB.setLine(line);
			dbMB.setShipmentMethod(masterBOL.getShipmentMethod());
			dbMB.setLoading(masterBOL.getLoading());
			dbMB.setTrailer(masterBOL.getTrailer());
			dbMB.setPilotName(masterBOL.getPilotName());
			dbMB.setPilotTel(masterBOL.getPilotTel());
			dbMB.setSealNumber(masterBOL.getSealNumber());
			dbMB.setAllShippedWeight(masterBOL.getAllShippedWeight());
			dbMB.setAllShippedVolume(masterBOL.getAllShippedVolume());
			dbMB.setShipToName(masterBOL.getShipToName());
			dbMB.setShipToAddress(masterBOL.getShipToAddress());
			dbMB.setShipToContact(masterBOL.getShipToContact());
			dbMB.setDescription(masterBOL.getDescription());
			commonDao.store(dbMB);
		}
	}

	public void addMasterBOLDetails(Long masterBOLId, List<Long> BOLIds) {
		MasterBOL masterBOL = commonDao.load(MasterBOL.class, masterBOLId);
		for (Long id : BOLIds) {
			BOL bol = this.load(BOL.class,id);
			if (bol.getMasterBOL() == null) {
				bol.setMasterBOL(masterBOL);
				masterBOL.getBOLs().add(bol);
				masterBOL.setAllShippedVolume(GlobalParamUtils.formatDecimalByType(masterBOL.getAllShippedVolume()+bol.getAllShippedVolume(), "maintainTableDecimal"));
				masterBOL.setAllShippedWeight(GlobalParamUtils.formatDecimalByType(masterBOL.getAllShippedWeight()+bol.getAllShippedWeight(), "maintainTableDecimal"));
			}
		}
		commonDao.store(masterBOL);
	}
	
	public void deleteMasterBOLDetails(Long masterBOLId, List<Long> BOLIds) {
		List<BOL> toBeRemoved = new ArrayList<BOL>();
		MasterBOL masterBOL = commonDao.load(MasterBOL.class, masterBOLId);
		for (BOL bol : masterBOL.getBOLs()) {
			if(BOLIds.contains(bol.getId())) {
				bol.setMasterBOL(null);
				commonDao.store(bol);
				masterBOL.setAllShippedVolume(GlobalParamUtils.formatDecimalByType(masterBOL.getAllShippedVolume()-bol.getAllShippedVolume(), "maintainTableDecimal"));
				masterBOL.setAllShippedWeight(GlobalParamUtils.formatDecimalByType(masterBOL.getAllShippedWeight()-bol.getAllShippedWeight(), "maintainTableDecimal"));
			}
		}
		masterBOL.getBOLs().removeAll(toBeRemoved);
		commonDao.store(masterBOL);
		
	}
	
	public void delete(List<Long> masterBOLIds) {
		for (Long masterBOLId : masterBOLIds) {
			MasterBOL masterBOL = commonDao.load(MasterBOL.class, masterBOLId);
			if (MasterBOLStatus.OPEN.equals(masterBOL.getStatus())) {
				String hql = " from PickTicket pickTicket where pickTicket.masterBOL.id = "+masterBOL.getId()+"";
				List<PickTicket> pts = commonDao.findByQuery(hql);
				for(PickTicket pt:pts){
					pt.setMasterBOL(null);
					this.commonDao.store(pt);
				}
				masterBOL.getBOLs().clear();
				commonDao.delete(masterBOL);
			}
		}
	}

	public void input(Long masterBOLId, String vehicle, Date inputDate, Long workerId) {
		MasterBOL masterBOL = this.load(MasterBOL.class, masterBOLId);
		masterBOL.setTrailer(vehicle);
		masterBOL.setInputDate(new Date());
		masterBOL.setStoreType("INPUT");
		masterBOL.setInputWorker(this.load(Worker.class, workerId));
	}

	public void output(Long masterBOLId, Date inputDate, Long workerId) {
		MasterBOL masterBOL = this.load(MasterBOL.class, masterBOLId);
		masterBOL.setOutputDate(new Date());
		masterBOL.setStoreType("OUTPUT");
		masterBOL.setOutputWorker(this.load(Worker.class, workerId));
	}

	@SuppressWarnings("unchecked")
	public void bolSign(BOLDetail detail) {
		detail = commonDao.load(BOLDetail.class, detail.getId());
		BOL bol = detail.getBol();
		for(BOLDetail bolDetail : bol.getBOLDetails()){
			//向BOLDetailLog中添加签收日志
			BOLDetailLog bdLog = EntityFactory.getEntity(BOLDetailLog.class);
			bdLog.setBolDetail(bolDetail);
			bdLog.setSingQuantity(bolDetail.getShipQuantity()-bolDetail.getSingQuantity()-bolDetail.getBadQuantity());
			bdLog.setBadQuantity(bolDetail.getBadQuantity());
			bdLog.setDeltaQuantity(0);
			
			bolDetail.setSingQuantity(bolDetail.getShipQuantity()-bolDetail.getBadQuantity());
			bolDetail.setBadQuantity(bolDetail.getBadQuantity());
			bolDetail.setDeltaQuantity(0);
			this.store(bdLog);
		}
		bol.setStatus(BOLStatus.SIGNED);
		if(null == bol.getSignDate()){
			bol.setSignDate(new Date());
		}	
		//看masterBol是否全部签收完成
		MasterBOL mBol = bol.getMasterBOL();
		mBol.setStatus(MasterBOLStatus.SIGNED);
		for(BOL boln : mBol.getBOLs()){
			if(!boln.getStatus().equals(BOLStatus.SIGNED)){
				mBol.setStatus(MasterBOLStatus.SIGNING);
				break;
			}
		}
		
		signBOLCaseDetail(bol);
	}
	
	//BOL签收的时候写入BOL笼车签收数量等于BOL发运数量
	private void signBOLCaseDetail(BOL bol){
		String hql = "select detail From BOLCaseDetail detail where detail.bol.id="+bol.getId();
		List<BOLCaseDetail> details = this.commonDao.findByQuery(hql);
		for(BOLCaseDetail detail:details){
			detail.setSignQuantity(detail.getShipQuantity());
			this.commonDao.store(detail);
		}

	}

	//装车单发车运抵
	public void arrivedMasterBOLDetails(Long id, List<Long> ids) {
		MasterBOL masterBOL = commonDao.load(MasterBOL.class,id);
		if(MasterBOLStatus.SHIP_ALL.equals(masterBOL.getStatus())){
			masterBOL.setStatus(MasterBOLStatus.ARRIVED);
		}
		for(Long bolId:ids){
			BOL bol = commonDao.load(BOL.class,bolId);
			bol.setArriveDate(new Date());//运抵时间
			bol.setStatus(BOLStatus.ARRIVED);
		}
		commonDao.store(masterBOL);
	}
	
	public String showBOLFee(Map param) throws IOException{
//		Long id = (Long)param.get("masterBOL.id");
////		MasterBOL masterBOL = commonDao.load(MasterBOL.class , id);
//		String feeRuleName = this.ruleName;
//		String feeCarrierCode = this.defaultCarrierCode;
//		
//		HttpClient httpClient = new HttpClient();
//
//		// 创建Post方法的实例
		String result = "";
//		PostMethod postMethod = new PostMethod(url);
//		
//		postMethod.setRequestHeader("Content-type", "application/octet-stream;charset=utf-8");
//		postMethod.setRequestHeader("e_username",UserHolder.getUser().getLoginName());
//
//		NameValuePair nvp[] = new NameValuePair[4];
//		nvp[0] =  new NameValuePair("fee_rule_name",feeRuleName);
//		nvp[1] =  new NameValuePair("fee_carrier_code",feeCarrierCode);
//		nvp[2] =  new NameValuePair("id",id.toString());
//		nvp[3] =  new NameValuePair("fee_orgnization_code",WarehouseHolder.getWarehouse().getCode());
//		postMethod.setQueryString(nvp);
//		
//		
//        ObjectInputStream in = null;
//		try {
//			// 执行getMethod
//			int statusCode = httpClient.executeMethod(postMethod);
//			if (statusCode == HttpStatus.SC_OK) {
//				in = new ObjectInputStream(postMethod.getResponseBodyAsStream());
//				Map rmap = new HashMap();
//				rmap = (Map)in.readObject();
//			    List<Object> list = new ArrayList<Object>();
//				for(Object o:rmap.keySet()){
//					list.add(o);
//				}
//				Collections.sort(list, new BeanComparator());
//				for(Object o:list){
//					result+=(o+":"+DoubleUtils.format2Fraction(rmap.get(o)))+"\r\n";
//				}
//			}else if(statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
//				result = postMethod.getResponseBodyAsString();
//			}else if(statusCode == HttpStatus.SC_GATEWAY_TIMEOUT) {
//				result = "网关超时";
//			}else if(statusCode == HttpStatus.SC_NOT_FOUND) {
//				result = "服务未提供";
//			}else if(statusCode == HttpStatus.SC_REQUEST_TIMEOUT) {
//				result = "请求超时";
//			}else if(statusCode == HttpStatus.SC_REQUEST_TOO_LONG) {
//				result = "请求太长";
//			}else {
//				System.err.println("Method failed: "+ postMethod.getStatusLine());
//				result = postMethod.getStatusText();
//			}
//		} catch (Exception e) {
//			e.printStackTrace();
//			result = e.getMessage();
//		} finally {
//			// 释放连接
//			postMethod.releaseConnection();
//		}
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public void bolSignByBOLDetail(BOLDetail detail) {
		BOLDetail bolDetail = this.load(BOLDetail.class,detail.getId());
		//如果当前签收数量和货损数量大于发运数量, 则不允许进行签收操作
		if(detail.getSingQuantity()+detail.getBadQuantity()+bolDetail.getSingQuantity()+bolDetail.getBadQuantity() > detail.getShipQuantity()){
			throw new BusinessException("signQuantity.more.than.shipQuantity");
		}
		double signQty = detail.getSingQuantity();
		double badQty = detail.getBadQuantity();
		String remark = detail.getRemark();
		
		bolDetail.setDeltaQuantity(bolDetail.getShipQuantity()-bolDetail.getSingQuantity()-bolDetail.getBadQuantity()-signQty-badQty);
		bolDetail.setSingQuantity(bolDetail.getSingQuantity()+signQty);
		bolDetail.setBadQuantity(bolDetail.getBadQuantity()+badQty);
		if(null != bolDetail.getRemark()){
			remark = bolDetail.getRemark() + remark;
		}
		bolDetail.setRemark(remark);
		if(null == bolDetail.getBol().getSignDate()){
			bolDetail.getBol().setSignDate(detail.getBol().getSignDate());
		}
		
		//向BOLDetailLog中添加签收日志
		BOLDetailLog bdLog = EntityFactory.getEntity(BOLDetailLog.class);
		bdLog.setBolDetail(bolDetail);
		bdLog.setSingQuantity(signQty);
		bdLog.setBadQuantity(badQty);
		bdLog.setDeltaQuantity(bolDetail.getDeltaQuantity());
		bdLog.setRemark(remark);
		this.store(bdLog);
		
		//检查该BOL是否已经签收完成, 如果签收完成则修改BOL状态为签收完成
		bolDetail.getBol().setStatus(BOLStatus.SIGNED);
		for(BOLDetail bolDetailn : bolDetail.getBol().getBOLDetails()){
			if(bolDetailn.getShipQuantity() > bolDetailn.getSingQuantity()+bolDetailn.getBadQuantity()){
				bolDetail.getBol().setStatus(BOLStatus.SIGNING);
				break;
			}
		}
		
		//检查当前MasterBOL是否已经签收完毕, 如果签收完成则修改状态为签收完成, 否则状态为签收中
		bolDetail.getBol().getMasterBOL().setStatus(MasterBOLStatus.SIGNED);
        for(BOL boln : bolDetail.getBol().getMasterBOL().getBOLs()){
        	if(!(boln.getStatus().equals(BOLStatus.SIGNED)) && signQty != 0){
        		bolDetail.getBol().getMasterBOL().setStatus(MasterBOLStatus.SIGNING);
        		break;
        	}
        }
        
        this.store(bolDetail);
        
        signBOLCaseDetail(bolDetail.getBol());
	}
	
	//刷新 订单数量 拣货数量 发运数量
	public void refreshMasterBOL(Long id) {
		MasterBOL masterBOL=this.load(MasterBOL.class, id);
		 List<Object[]> objs =  commonDao.findByQuery("select COALESCE(sum(pickTicket.orderQuantity),0),COALESCE(sum(pickTicket.pickedQuantity),0),COALESCE(sum(pickTicket.shippedQuantity),0)  from PickTicket pickTicket where pickTicket.masterBOL.id=:id ",
					new String[] { "id"},new Object[] {id});
			if(objs.size()>0){
				Object[] obj=objs.get(0);
				masterBOL.setOrderQuantity((Double)obj[0]);
				masterBOL.setPickQuantity((Double)obj[1]);
				masterBOL.setShipQuantity((Double)obj[2]);
			}
		if(masterBOL.getPickQuantity()==masterBOL.getOrderQuantity()) {
			masterBOL.setStatus(MasterBOLStatus.PICK_ALL);
			if(masterBOL.getShipQuantity()==masterBOL.getOrderQuantity()) {
				masterBOL.setStatus(MasterBOLStatus.SHIP_ALL);
			}
		}else if(masterBOL.getPickQuantity()>masterBOL.getOrderQuantity()){
			masterBOL.setStatus(MasterBOLStatus.PICKUP);
		}else {
			//masterBOL.setStatus(MasterBOLStatus.OPEN);
		}
		commonDao.store(masterBOL);
	}

	@Override
	public void saveMasterBOLDetails(Long masterBOLId, List<Long> ids) {
			MasterBOL masterBOL = commonDao.load(MasterBOL.class, masterBOLId);
			
		for(Long id : ids) {
			PickTicket pickTicket=this.load(PickTicket.class, id);
				if(masterBOL.getLine()==null) {
					if(pickTicket.getLineName()!=null&&!pickTicket.getLineName().equals("")){
						List<Line> lines=this.commonDao.findByQuery("from Line l where l.lineName=:lineName",
								new String[]{"lineName"},new Object[]{pickTicket.getLineName()});
						if(lines.size()>0){
							masterBOL.setLine(lines.get(0));
						}
					}
				masterBOL.setShipToName(pickTicket.getShipToName());//收货人名称
				masterBOL.setShipToAddress(pickTicket.getShipToAddress());
				if(pickTicket.getShipToContact()!=null) {
					masterBOL.setShipToContact(pickTicket.getShipToContact());
				}
			}
			masterBOL.setDescription(pickTicket.getDescription());//描述
			masterBOL.setCompany(pickTicket.getCompany());//添加货主到masterBOL
			pickTicket.setMasterBOL(masterBOL);
			commonDao.store(pickTicket);
		}
		
		refreshMasterBOL(masterBOLId);
		
	}
	
	@Override
	public void autoMasterBOL() {
		List<PickTicket> pts=this.commonDao.findByQuery("from PickTicket pt where pt.status in ('ACTIVE','ALLOCATE','PICK_ALL') and pt.masterBOL.id is null and pt.lineName is not null ");
		for(PickTicket pt :pts){
			List<MasterBOL> ms=null;
			Line line=null;
			Date orderDate=null;
			if(pt.getCompany().getCode().equals("HLX")){
				orderDate=pt.getShipDate();
				ms=this.commonDao.findByQuery("from MasterBOL b where b.pilotName=:pilotName and b.shipQuantity<=0 and to_char(b.outputDate,'yyyy-mm-dd')=:outputDate",
						new String[]{"pilotName","outputDate"},new Object[]{pt.getLineName(),DateUtil.formatDateYMDToStr(orderDate)});
			}else{
				List<Line> lines=this.commonDao.findByQuery("from Line l where l.lineName=:lineName",
						new String[]{"lineName"},new Object[]{pt.getLineName()});
				if(lines.size()>0){
					orderDate=pt.getOrderDate();
					ms=this.commonDao.findByQuery("from MasterBOL b where b.line.id=:lineId and b.shipQuantity<=0 and to_char(b.outputDate,'yyyy-mm-dd')=:outputDate",
							new String[]{"lineId","outputDate"},new Object[]{lines.get(0).getId(),DateUtil.formatDateYMDToStr(orderDate)});
					line=lines.get(0);
				}else{
					continue;
				}
			}
			MasterBOL mb=null;
			if(ms.size()>0){
				mb=ms.get(0);
				mb.setShipToName(pt.getShipToName());//收货人名称
				mb.setShipToAddress(pt.getShipToAddress());
				if(pt.getShipToContact()!=null) {
					mb.setShipToContact(pt.getShipToContact());
				}
			}else{
				mb=EntityFactory.getEntity(MasterBOL.class);
				mb.setOutputDate(orderDate);
				mb.setLine(line);
				mb.setWarehouse(WarehouseHolder.getWarehouse());
				mb.setStatus(MasterBOLStatus.OPEN);
				mb.setUserTracking();
				mb.setCode(bussinessCodeManager.getCodeForYm("MB", 4));
				if(pt.getCompany().getCode().equals(CompanyCode.HLX)){
					mb.setTrailer(pt.getLictrailer());
					mb.setPilotName(pt.getLineName());
				}
				mb.setCompany(pt.getCompany());
			}
			mb.setDescription(pt.getDescription());//描述
			pt.setMasterBOL(mb);
			commonDao.store(pt);
			this.commonDao.store(mb);
			refreshMasterBOL(mb.getId());
		}
		
			
	}
	

	@Override
	public void removeMasterBOLDetails(Long masterBOLId, List<Long> ids) {
		MasterBOL masterBOL = commonDao.load(MasterBOL.class, masterBOLId);
		Long masterBOLid=null;
		for(Long id : ids) {
			PickTicket pickTicket=this.load(PickTicket.class, id);
			masterBOLid=pickTicket.getMasterBOL().getId();
			pickTicket.setMasterBOL(null);
			
			commonDao.store(pickTicket);
		}
		if(masterBOLid!=null) {
			refreshMasterBOL(masterBOLid);
		}
		
	}

	@Override
	public void shipConfirm(Long masterBOLId, Long workerId) {
		MasterBOL masterBOL = commonDao.load(MasterBOL.class,masterBOLId);
		String hql = " from PickTicket pickTicket where pickTicket.masterBOL.id = "+masterBOL.getId()+"";
		List<PickTicket> PickTickets = commonDao.findByQuery(hql);
		if (MasterBOLStatus.OPEN.equals(masterBOL.getStatus())) {
			for (PickTicket p :PickTickets) {
				p.setStatus(PickTicketStatus.CLOSE);
				p.setShippedQuantity(p.getPickedQuantity());
				commonDao.store(p);
			}
			masterBOL.setLeaveTime(new Date());
			masterBOL.setStatus(MasterBOLStatus.SHIP_ALL);
			commonDao.store(masterBOL);
			refreshMasterBOL(masterBOLId);
		}
		
	}

	/**
	 * 扣减预分配表中的数量
	 * @param bol
	 */
	@SuppressWarnings("unchecked")
	public void updatePreAllocate(Long pickTicketId) {
		//扣减预分配表流程调整
		//1、根据PickTicketDetail中preAllocatedLot依次扣减PreAllocate
		//2、如果PreAllocate中记录的数量被扣减完毕，则直接删除PreAllocate记录
		//3、根据PickTicketDetail中item依次扣减PreAllocate
		//4、如果PreAllocate中记录的数量被扣减完毕，则直接删除PreAllocate记录
		PickTicket p = commonDao.load(PickTicket.class, pickTicketId);
		List<PreAllocate> preAllocates = commonDao.findByNamedQuery("getPreAllocateByCondition", 
				new String[]{"code", "warehouseId"}, 
				new Object[]{p.getCode(), WarehouseHolder.getWarehouse().getId()});
		Map<PickTicketDetail, Double> details = new HashMap<PickTicketDetail, Double>();
		for (PickTicketDetail detail : p.getPickTicketDetails()) {
			if (details == null || !details.containsKey(detail)) {
				details.put(detail, detail.getPickedQuantity());
			} else {
				double qty = details.get(detail);
				qty += detail.getPickedQuantity();
				details.put(detail, qty);
			}
		}
		List<PreAllocate> toBeRemoved = new ArrayList<PreAllocate>();
		
		//第一次循环
		for (PickTicketDetail dtl : details.keySet()) {
			for (PreAllocate preAllocate : preAllocates) {
				if (preAllocate.getItem().equals(dtl.getItem())
						&& ((preAllocate.getLot()==null && dtl.getPreAllocatedLot()==null) 
						|| (preAllocate.getLot().equals(dtl.getPreAllocatedLot())))) {
					if (details.get(dtl) > preAllocate.getPreAllocatedQuantity()) {
						details.put(dtl, details.get(dtl) - preAllocate.getPreAllocatedQuantity());
						toBeRemoved.add(preAllocate);
					} else {
						preAllocate.setPreAllocatedQuantity(preAllocate.getPreAllocatedQuantity() - details.get(dtl));
						if (preAllocate.getPreAllocatedQuantity() == 0) {
							toBeRemoved.add(preAllocate);
						}
						details.put(dtl, 0.0);
					}
				}
			}
		}
		commonDao.deleteAll(toBeRemoved);
		toBeRemoved.clear();
		
		
		//第二次循环
		for (PickTicketDetail dtl : details.keySet()) {
			if (details.get(dtl) <= 0) {
				continue;
			}
			for (PreAllocate preAllocate : preAllocates) {
				if (preAllocate.getItem().equals(dtl.getItem())) {
					if (details.get(dtl) > preAllocate.getPreAllocatedQuantity()) {
						details.put(dtl, details.get(dtl) - preAllocate.getPreAllocatedQuantity());
						toBeRemoved.add(preAllocate);
					} else {
						preAllocate.setPreAllocatedQuantity(preAllocate.getPreAllocatedQuantity() - details.get(dtl));
						if (preAllocate.getPreAllocatedQuantity() == 0) {
							toBeRemoved.add(preAllocate);
						}
						details.put(dtl, 0.0);
					}
				}
			}
		}
		commonDao.deleteAll(toBeRemoved);
	}
	
	//刷新发运数量
	public void updatePickTicketQuantity(List<Long> pickTicketId){
		if(pickTicketId.size()>0){
		for(Long id : pickTicketId ){
			updatePickTicketQuantity(id);
		}
		}
	}
	/**更新PickTicket发运数量和预分配数量*/
	public void updatePickTicketQuantity(Long pickTicketId){
		PickTicket p = commonDao.load(PickTicket.class, pickTicketId);
		double q=0;
		List<PickTicketDetail> ptds=this.commonDao.findByQuery(" from PickTicketDetail pd where pd.pickTicket.id ="+pickTicketId);
		double shipQty=0;
		double pickQty=0;
		double fpQty=0;
		for(PickTicketDetail ptd:ptds){
			q+=ptd.getShippedQuantity();
			fpQty+=ptd.getAllocatedQuantity();
			pickQty+=ptd.getPickedQuantity();
			shipQty+=ptd.getShippedQuantity();
		}
		p.setShippedQuantity(shipQty);
		p.setPickedQuantity(pickQty);
		p.setAllocatedQuantity(fpQty);
		this.commonDao.store(p);
		
		p.setShippedQuantity(q);
		if(p.shippedAllDetails()&&p.getShippedQuantity()>=p.getOrderQuantity()){
//			//若有箱子，则设置为出场箱
//			 if(p.getContainer()!=null){
//				 p.getContainer().setOutDate(new Date());
//				 p.getContainer().setStatus(ContainerStatus.OUTBOUNDBOX);
//			 }
			p.setStatus(PickTicketStatus.CLOSE);
//			refreshStockInfo(pickTicketId);
		}else{
			p.setStatus(PickTicketStatus.SHIP_PART);
		}
//		p.setShipDate(new Date());
		p.setUserTracking();
		this.commonDao.store(p);
	}
	
}