package com.dev.swms.server.model.shipping;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

import com.dev.swms.server.model.abstractEntity.AbstractMoveDoc;
import com.dev.swms.server.model.abstractEntity.AbstractMoveDocDetail;
import com.dev.swms.server.model.base.Address;
import com.dev.swms.server.model.base.BillType;
import com.dev.swms.server.model.base.BoxModel;
import com.dev.swms.server.model.base.Contact;
import com.dev.swms.server.model.base.Location;
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.TransSite;
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.inventory.Inventory;
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.energy.server.exception.BusinessException;
import com.dev.energy.server.web.security.UserHolder;

public class PickTicket extends AbstractMoveDoc {
	private static final long serialVersionUID = 2753846656286058862L;
	/** 定义单据类型 */
	public final static String SO_SWAP = "SO_SWAP";
	/** 所属仓库 */
	private Warehouse warehouse;
	/** 所属客户 */
	private Structure company;
	/** 库区 */
	private WarehouseArea zone;
	/** 所属库区 */
	private WarehouseArea zone1;//收货库仓库
	/** 所属库区 */
	private WarehouseArea zone2;//出库仓库
	private String outType;//出库类型
	
	/** 发货单号 */
	private String code;
	/** 相关单据号1 */
	private String relatedBill1;
	/** 相关单据号2 */
	private String relatedBill2;
	/** 相关单据号3 */
	private String relatedBill3;//其他出库
	/** 状态 */
	private String planStatus;
	/** 状态 */
	private String status;
	/** 订单日期 */
	private Date orderDate;
	/** 发货日期 */
	private Date shipDate;
	/** 到达日期 */
	private Date receivedDate;
	/** 收货方名称 */
	private String shipToName;
	/** 收货方地址 */
	private Address shipToAddress;
	/** 收货方联系方式 */
	private Contact shipToContact;
	/** 订单数量 */
	private double orderQuantity;
	/** 预分配数量 */
	private double preAllocatedQuantity;
	/** 已分配数量 */
	private double allocatedQuantity;
	/** 拣货数量 */
	private double pickedQuantity;
	/** 已发运数量 */
	private double shippedQuantity;
	/** 发货单明细 */
	private Set<PickTicketDetail> pickTicketDetails = new HashSet<PickTicketDetail>();
	/** 最后修改人ID */
	private Long userID;
	/** 最后修改人姓名 */
	private String userName;
	/** 最后修改时间 */
	private Date updateTime;
	/** 单据类型 */
	private BillType billType;
	/** 波次号 */
	private String waveCode;
	/** 所属波次单 */
	private WaveDoc waveDoc;
	/** 收货人 */
	private Structure customer;
	/** 集货编号 */
	private String collectNo;
	/** 要求到达日期 */
	private Date requireArriveDate;
	/** 预计发货日期 */
	private Date intendShipDate;
	/** 承运商 */
	private Structure carrier;
	/** 发货预约开始时间 */
	private Date shipDateStart;
	/** 发货预约结束时间 */
	private Date shipDateEnd;
	/** 月台 */
	private Location dock;
	/** 线边接收数量，包箱数量*/ 
	private double packageQuantity;
	/** BOL数量 */
	private double BOLQuantity;//纯需要数量
	/** 优先级 -是否设变*/
	private int priority = 0;
	/** 是否越库 */
	private boolean crossStocking;
	/** 出发地 */
	private TransSite startPosition;
	/** 目的地 */
	private TransSite aimPosition;
	/** 对应库间补货单 */
	private InventoryApply inventoryApply;
	/** 单据打印标志,份数 */
	private int printCount = 0;
	/** 税别 */
	private String applyDoc;
	/** 是否创建bol */
	private Boolean beCreateBOL = Boolean.FALSE;
	/**箱子型号*/
	private BoxModel boxModel;
	/** 运输方式 **/
	private String shipmentMethod; 
	/** 备注 */
	private String description;
	
	private Long executePlan;
	
	private String executePlanNo;//部品种类
	
	private String lineName;//线路名称
	
	private Store store;
	
	private Prewave prewave;//预波次
	
	private double volume;//体积
	
	private double weight;//重量
	
	private double realWeight;//--毛重
	
	private MasterBOL masterBOL;//装车单
	/**  */
	private String sourceId;
	/**  */
	private String sourceType;
	
	private String equatedQuantity;//等同数量
	/**司机*/
	private String driverName;//发货联系人
	/**车号*/
	private String lictrailer;//发货联系方式
	private long sequenceNo;//关联发货单表
	
	/** 作业人员 */
	private Worker worker1;
	/** 作业人员 */
	private Worker worker2;
	/** 作业人员 */
	private Worker worker3;
	/** 作业人员 */
	private Worker worker4;
	
	private String shipmentType;//发运类型

	private String licenseNO;//车牌号
	
	private String  expressNO;//快递单号
	private String  expressName;//快递名称
	private String  platformCode;//平台订单代码
	private String  sellerMemo;//卖家备注
	private String  buyerMemo;//买家留言
	
	
	private double shipmentTrayNO;//发运托盘数
	
	private Set<SignFile> files = new HashSet<SignFile>(); // 附件清单
	
	//包装类型1、数量1，包装类型2，数量2，包装类型3，数量3
	private String packType1;//机种
	private double quantity1=0;//线边数量
	private String packType2;
	private double quantity2=0;//在途数量
	private String packType3;
	private double quantity3=0;//需要数量
	
	private double quantity4=0;//备货数量汇总(根据份数拆分)
	/** 发货 */
	private String fhBy;
	/** 接收 */
	private String slBy;
	/** 收料日期 */
	private Date tlDate;
	/** 投料 */
	private String tlBy;
	/** 投料日期 */
	private Date slDate;
	/** 投料数量 */
	private double tlQty=0;
	
	
	public Date getTlDate() {
		return tlDate;
	}

	public void setTlDate(Date tlDate) {
		this.tlDate = tlDate;
	}

	public String getTlBy() {
		return tlBy;
	}

	public void setTlBy(String tlBy) {
		this.tlBy = tlBy;
	}

	public double getTlQty() {
		return tlQty;
	}

	public void setTlQty(double tlQty) {
		this.tlQty = tlQty;
	}


	public Date getSlDate() {
		return slDate;
	}

	public void setSlDate(Date slDate) {
		this.slDate = slDate;
	}

	public String getFhBy() {
		return fhBy;
	}

	public void setFhBy(String fhBy) {
		this.fhBy = fhBy;
	}

	

	public String getSlBy() {
		return slBy;
	}

	public void setSlBy(String slBy) {
		this.slBy = slBy;
	}

	public double getQuantity4() {
		return quantity4;
	}

	public void setQuantity4(double quantity4) {
		this.quantity4 = quantity4;
	}

	public WarehouseArea getZone1() {
		return zone1;
	}

	public void setZone1(WarehouseArea zone1) {
		this.zone1 = zone1;
	}

	public WarehouseArea getZone2() {
		return zone2;
	}

	public void setZone2(WarehouseArea zone2) {
		this.zone2 = zone2;
	}

	public String getOutType() {
		return outType;
	}

	public void setOutType(String outType) {
		this.outType = outType;
	}

	public WarehouseArea getZone() {
		return zone;
	}

	public void setZone(WarehouseArea zone) {
		this.zone = zone;
	}

	public String getPlanStatus() {
		return planStatus;
	}

	public void setPlanStatus(String planStatus) {
		this.planStatus = planStatus;
	}

	public String getSellerMemo() {
		return sellerMemo;
	}

	public void setSellerMemo(String sellerMemo) {
		this.sellerMemo = sellerMemo;
	}

	public String getBuyerMemo() {
		return buyerMemo;
	}

	public void setBuyerMemo(String buyerMemo) {
		this.buyerMemo = buyerMemo;
	}

	public String getExpressName() {
		return expressName;
	}

	public void setExpressName(String expressName) {
		this.expressName = expressName;
	}

	public String getPlatformCode() {
		return platformCode;
	}

	public void setPlatformCode(String platformCode) {
		this.platformCode = platformCode;
	}

	public String getPackType1() {
		return packType1;
	}

	public void setPackType1(String packType1) {
		this.packType1 = packType1;
	}

	public double getQuantity1() {
		return quantity1;
	}

	public void setQuantity1(double quantity1) {
		this.quantity1 = quantity1;
	}

	public String getPackType2() {
		return packType2;
	}

	public void setPackType2(String packType2) {
		this.packType2 = packType2;
	}

	public double getQuantity2() {
		return quantity2;
	}

	public void setQuantity2(double quantity2) {
		this.quantity2 = quantity2;
	}

	public String getPackType3() {
		return packType3;
	}

	public void setPackType3(String packType3) {
		this.packType3 = packType3;
	}

	public double getQuantity3() {
		return quantity3;
	}

	public void setQuantity3(double quantity3) {
		this.quantity3 = quantity3;
	}

	public double getRealWeight() {
		return realWeight;
	}

	public void setRealWeight(double realWeight) {
		this.realWeight = realWeight;
	}

	public double getShipmentTrayNO() {
		return shipmentTrayNO;
	}

	public void setShipmentTrayNO(double shipmentTrayNO) {
		this.shipmentTrayNO = shipmentTrayNO;
	}

	public String getLicenseNO() {
		return licenseNO;
	}

	public void setLicenseNO(String licenseNO) {
		this.licenseNO = licenseNO;
	}

	public String getExpressNO() {
		return expressNO;
	}

	public void setExpressNO(String expressNO) {
		this.expressNO = expressNO;
	}

	public String getShipmentType() {
		return shipmentType;
	}

	public void setShipmentType(String shipmentType) {
		this.shipmentType = shipmentType;
	}

	public Worker getWorker1() {
		return worker1;
	}

	public void setWorker1(Worker worker1) {
		this.worker1 = worker1;
	}

	public Worker getWorker2() {
		return worker2;
	}

	public void setWorker2(Worker worker2) {
		this.worker2 = worker2;
	}

	public Worker getWorker3() {
		return worker3;
	}

	public void setWorker3(Worker worker3) {
		this.worker3 = worker3;
	}

	public Worker getWorker4() {
		return worker4;
	}

	public void setWorker4(Worker worker4) {
		this.worker4 = worker4;
	}

	
	public long getSequenceNo() {
		return sequenceNo;
	}

	public void setSequenceNo(long sequenceNo) {
		this.sequenceNo = sequenceNo;
	}

	public void setSequenceNo(int sequenceNo) {
		this.sequenceNo = sequenceNo;
	}

	public String getDriverName() {
		return driverName;
	}

	public void setDriverName(String driverName) {
		this.driverName = driverName;
	}

	public String getLictrailer() {
		return lictrailer;
	}

	public void setLictrailer(String lictrailer) {
		this.lictrailer = lictrailer;
	}

	public String getEquatedQuantity() {
		return equatedQuantity;
	}

	public void setEquatedQuantity(String equatedQuantity) {
		this.equatedQuantity = equatedQuantity;
	}

	public String getSourceId() {
		return sourceId;
	}

	public void setSourceId(String sourceId) {
		this.sourceId = sourceId;
	}

	public String getSourceType() {
		return sourceType;
	}

	public void setSourceType(String sourceType) {
		this.sourceType = sourceType;
	}

	public MasterBOL getMasterBOL() {
		return masterBOL;
	}

	public void setMasterBOL(MasterBOL masterBOL) {
		this.masterBOL = masterBOL;
	}


	public WaveDoc getWaveDoc() {
		return waveDoc;
	}

	public void setWaveDoc(WaveDoc waveDoc) {
		this.waveDoc = waveDoc;
	}

	public double getVolume() {
		return volume;
	}

	public void setVolume(double volume) {
		this.volume = volume;
	}

	public double getWeight() {
		return weight;
	}

	public void setWeight(double weight) {
		this.weight = weight;
	}

	public Prewave getPrewave() {
		return prewave;
	}

	public void setPrewave(Prewave prewave) {
		this.prewave = prewave;
	}

	public Store getStore() {
		return store;
	}

	public void setStore(Store store) {
		this.store = store;
	}

	public String getLineName() {
		return lineName;
	}

	public void setLineName(String lineName) {
		this.lineName = lineName;
	}

	public String getExecutePlanNo() {
		return executePlanNo;
	}

	public void setExecutePlanNo(String executePlanNo) {
		this.executePlanNo = executePlanNo;
	}

	public Long getExecutePlan() {
		return executePlan;
	}

	public void setExecutePlan(Long executePlan) {
		this.executePlan = executePlan;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public String getShipmentMethod() {
		return shipmentMethod;
	}

	public void setShipmentMethod(String shipmentMethod) {
		this.shipmentMethod = shipmentMethod;
	}

	public Boolean getBeCreateBOL() {
		if ((this.BOLQuantity > 0 || PickTicketStatus.SHIP_ALL.equals(this.status))) {
			return Boolean.TRUE;
		}
		return Boolean.FALSE;
	}
	
	public BoxModel getBoxModel() {
		return boxModel;
	}

	public void setBoxModel(BoxModel boxModel) {
		this.boxModel = boxModel;
	}

	public void setBeCreateBOL(Boolean beCreateBOL) {
		this.beCreateBOL = beCreateBOL;
	}
	
	public int getPrintCount() {
		return printCount;
	}
	
	public void setPrintCount(int printCount) {
		this.printCount = printCount;
	}
	
	public String getApplyDoc() {
		return applyDoc;
	}

	public void setApplyDoc(String applyDoc) {
		this.applyDoc = applyDoc;
	}

	public InventoryApply getInventoryApply() {
		return inventoryApply;
	}

	public void setInventoryApply(InventoryApply inventoryApply) {
		this.inventoryApply = inventoryApply;
	}

	public TransSite getStartPosition() {
		return startPosition;
	}

	public void setStartPosition(TransSite startPosition) {
		this.startPosition = startPosition;
	}

	public TransSite getAimPosition() {
		return aimPosition;
	}

	public void setAimPosition(TransSite aimPosition) {
		this.aimPosition = aimPosition;
	}

	public double getPackageQuantity() {
		return packageQuantity;
	}
	
	public int getPriority() {
		return priority;
	}

	public void setPriority(int priority) {
		this.priority = priority;
	}

	public void setPackageQuantity(double packageQuantity) {
		this.packageQuantity = packageQuantity;
	}

	public double getBOLQuantity() {
		return BOLQuantity;
	}

	public void setBOLQuantity(double quantity) {
		BOLQuantity = quantity;
	}

	public Location getDock() {
		return dock;
	}

	public void setDock(Location dock) {
		this.dock = dock;
	}

	public Date getShipDateEnd() {
		return shipDateEnd;
	}

	public void setShipDateEnd(Date shipDateEnd) {
		this.shipDateEnd = shipDateEnd;
	}

	public Date getShipDateStart() {
		return shipDateStart;
	}

	public void setShipDateStart(Date shipDateStart) {
		this.shipDateStart = shipDateStart;
	}

	public PickTicket(){
		
	}

	public double getPreAllocatedQuantity() {
		return preAllocatedQuantity;
	}
	public void setPreAllocatedQuantity(double preAllocatedQuantity) {
		this.preAllocatedQuantity = preAllocatedQuantity;
	}
	public Structure getCarrier() {
		return carrier;
	}
	public void setCarrier(Structure carrier) {
		this.carrier = carrier;
	}
	public Date getIntendShipDate() {
		return intendShipDate;
	}
	public void setIntendShipDate(Date intendShipDate) {
		this.intendShipDate = intendShipDate;
	}
	public Date getRequireArriveDate() {
		return requireArriveDate;
	}
	public void setRequireArriveDate(Date requireArriveDate) {
		this.requireArriveDate = requireArriveDate;
	}
	public String getCollectNo() {
		return collectNo;
	}
	public void setCollectNo(String collectNo) {
		this.collectNo = collectNo;
	}
	public Structure getCustomer() {
		return customer;
	}
	public void setCustomer(Structure customer) {
		this.customer = customer;
	}
    public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public Structure getCompany() {
		return company;
	}
	public void setCompany(Structure company) {
		this.company = company;
	}
	public Date getOrderDate() {
		return orderDate;
	}
	public void setOrderDate(Date orderDate) {
		this.orderDate = orderDate;
	}
	public double getOrderQuantity() {
		return orderQuantity;
	}
	public void setOrderQuantity(double orderQuantity) {
		this.orderQuantity = orderQuantity;
	}
	public Date getReceivedDate() {
		return receivedDate;
	}
	public void setReceivedDate(Date receivedDate) {
		this.receivedDate = receivedDate;
	}
	public String getRelatedBill1() {
		return relatedBill1;
	}
	public void setRelatedBill1(String relatedBill1) {
		this.relatedBill1 = relatedBill1;
	}
	public String getRelatedBill2() {
		return relatedBill2;
	}
	public void setRelatedBill2(String relatedBill2) {
		this.relatedBill2 = relatedBill2;
	}
	public String getRelatedBill3() {
		return relatedBill3;
	}
	public void setRelatedBill3(String relatedBill3) {
		this.relatedBill3 = relatedBill3;
	}
	public Date getShipDate() {
		return shipDate;
	}
	public void setShipDate(Date shipDate) {
		this.shipDate = shipDate;
	}
	public double getShippedQuantity() {
		return shippedQuantity;
	}
	public void setShippedQuantity(double shippedQuantity) {
		this.shippedQuantity = shippedQuantity;
	}
	public Address getShipToAddress() {
		return shipToAddress;
	}
	public void setShipToAddress(Address shipToAddress) {
		this.shipToAddress = shipToAddress;
	}
	public Contact getShipToContact() {
		return shipToContact;
	}
	public void setShipToContact(Contact shipToContact) {
		this.shipToContact = shipToContact;
	}
	public String getShipToName() {
		return shipToName;
	}
	public void setShipToName(String shipToName) {
		this.shipToName = shipToName;
	}
	public String getStatus() {
		return status;
	}
	public void setStatus(String status) {
		this.status = status;
	}
	public Warehouse getWarehouse() {
		return warehouse;
	}
	public void setWarehouse(Warehouse warehouse) {
		this.warehouse = warehouse;
	}	
	public double getAllocatedQuantity() {
		return allocatedQuantity;
	}
	public void setAllocatedQuantity(double allocatedQuantity) {
		this.allocatedQuantity = allocatedQuantity;
	}	
	public Set<PickTicketDetail> getPickTicketDetails() {
		return pickTicketDetails;
	}
	public void setPickTicketDetails(Set<PickTicketDetail> pickTicketDetails) {
		this.pickTicketDetails = pickTicketDetails;
	}	

	public Date getUpdateTime() {
		return updateTime;
	}
	public void setUpdateTime(Date updateTime) {
		this.updateTime = updateTime;
	}
	public Long getUserID() {
		return userID;
	}
	public void setUserID(Long userID) {
		this.userID = userID;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public BillType getBillType() {
		return billType;
	}
	public void setBillType(BillType billType) {
		this.billType = billType;
	}
	public double getPickedQuantity() {
		return pickedQuantity;
	}
	
	
	public Set<SignFile> getFiles() {
		return files;
	}

	public void setFiles(Set<SignFile> files) {
		this.files = files;
	}

	public void setPickedQuantity(double pickedQuantity) {
		this.pickedQuantity = pickedQuantity;
	}	

	@Override
	public boolean equals(final Object other) {
		if (!(other instanceof PickTicket))
			return false;
		PickTicket castOther = (PickTicket) other;
		return new EqualsBuilder().append(warehouse, castOther.warehouse)
				.append(company, castOther.company)
				.append(code, castOther.code).append(billType,
						castOther.billType).isEquals();
	}

	@Override
	public int hashCode() {
		return new HashCodeBuilder().append(warehouse).append(company).append(
				code).append(billType).toHashCode();
	}

	/**
	 * 拣货确认
	 * @param picked
	 * @param convertFigure
	 * @param detailConvertFigure
	 */
	public void pickConfirm(double pickedQuantity,double weight){
		if (!(PickTicketStatus.ALLOCATE.equals(this.status) 
				|| PickTicketStatus.PICKUP.equals(this.status) 
				|| PickTicketStatus.SHIP_PART.equals(this.status))) {
			throw new BusinessException("pickTicket.status.error");
		}
		this.pickedQuantity += pickedQuantity;
		this.weight+=weight;
		//拣货确认后状态判断
		if (this.orderQuantity == this.pickedQuantity) {
			this.status = PickTicketStatus.PICK_ALL;
		} else {
			this.status = PickTicketStatus.PICKUP;
		}
	}
	
	/**
	 * 记录收货单的最新修改用户和修改时间信息
	 *
	 */
	public void setUserTracking() {
		this.setUserID(UserHolder.getUser().getId());
		this.setUserName(UserHolder.getUser().getName());
		this.setUpdateTime(new Date());
	}

	/**
	 * 对指定的发货单明细分配
	 * 只能对打开、已分配或部分发运状态的发货单做拣货分配
	 * @param moveDocDetail 待分配的发货单明细
	 * @param inventory 待分配的库存
	 * @param quantity 分配数量
	 */
	public Task allocate(String bhCode,AbstractMoveDocDetail moveDocDetail, Inventory inventory, double quantity) {
		if (!(PickTicketStatus.PREALLOCATE.equals(this.status) 
				|| PickTicketStatus.ALLOCATE.equals(this.status) 
				|| PickTicketStatus.PICKUP.equals(this.status)
				|| PickTicketStatus.SHIP_PART.equals(this.status)
				|| (PickTicketStatus.OPEN.equals(this.status))
				|| (PickTicketStatus.ACTIVE.equals(this.status))// && !this.getCompany().getCompanyWorkRule().isInvSubscribe()) 
				)) {
			throw new BusinessException("pickTicket.status.error");
		}
		Task t=moveDocDetail.allocate(bhCode,inventory, quantity);
		this.allocatedQuantity += quantity;
//		if (DoubleUtils.compareByPrecision(this.allocatedQuantity, this.orderQuantity, 
//				moveDocDetail.getPackageUnit().getPrecision())==0) {
//			this.setApplyDoc("");
//		}
		this.status = PickTicketStatus.ALLOCATE;
        setUserTracking();
        return t;
	}
	
	/**
	 * 对指定发货单明细取消分配
	 * 只能对已分配或发运中的发货单取消分配
	 * @param quantity 取消分配数量
	 */
	public void unallocate(double quantity) {
		if (!(PickTicketStatus.ALLOCATE.equals(this.status) 
				|| PickTicketStatus.SHIP_PART.equals(this.status)
				|| PickTicketStatus.PICKUP.equals(this.status))) {
			throw new BusinessException("pickTicket.status.error");
		}
		this.allocatedQuantity -= quantity;
		if (this.allocatedQuantity == 0 && !PickTicketStatus.CLOSE.equals(this.status)) {
			if(this.company.getCompanyWorkRule()==null){
				this.status = PickTicketStatus.ACTIVE;
			}else{
				this.status = PickTicketStatus.PREALLOCATE;
			}
		}
        setUserTracking();
	}
	
	/**
	 * 关于大范围与小范围的合并，算法繁琐  可能不存在合并，但是bol分配还原的时候就有难度
	 * @param compDetail
	 * @return
	 */
    public PickTicketDetail getPickTicketDetail(PickTicketDetail compDetail) {
    	//TODO 大范围与小范围的合并
        if (pickTicketDetails != null) {
            for (PickTicketDetail detail : pickTicketDetails) {
                if (detail.getItem().getId().equals(compDetail.getItem().getId()) &&
                		detail.getPackageUnit().getId().equals(compDetail.getPackageUnit().getId()) &&
                		detail.getCaCoefficient()==compDetail.getCaCoefficient() &&
                		((detail.getNewLotInfo()==null && compDetail.getNewLotInfo()==null) 
                				|| (detail.getNewLotInfo()!=null && compDetail.getNewLotInfo()!=null && detail.getNewLotInfo().hashCode() == compDetail.getNewLotInfo().hashCode()))) {
                    return detail;
                }
            }
        }
        return null;
    }
    

    /**
     * 增加拣货单明细，并增加拣货单的期待数量
     * @param pickTicketDetail 待增加的拣货单明细
     */
    public void addPickTicketDetail(PickTicketDetail pickTicketDetail) {	
        pickTicketDetail.setPickTicket(this);
        this.pickTicketDetails.add(pickTicketDetail);
        this.orderQuantity += pickTicketDetail.getOrderQtyOfMasterUnit();
    }
    
    /**
     * 增加明细和头的订货数量
     * @param existPickTicketDetail
     * @param orderQuantity
     */
    public void addOrderQuantity(PickTicketDetail pickTicketDetail, double orderQuantity ,PackageUnit unit) {
        this.orderQuantity += orderQuantity*unit.getConvertFigure();
        pickTicketDetail.addOrderQuantity(orderQuantity,unit);
    }
    
    
    /**
     * 删除拣货单明细，并扣减拣货单的订单数量
     * @param pickTicketDetailIds 待删除拣货单明细的ID集合
     */
    public void removeDetails(List<Long> pickTicketDetailIds) {
        if (this.pickTicketDetails != null && PickTicketStatus.OPEN.equals(this.status)) {
            Set<PickTicketDetail> toBeRemoved = new HashSet<PickTicketDetail>();
            for (PickTicketDetail detail : pickTicketDetails) {
                if (pickTicketDetailIds.contains(detail.getId())) {
                    toBeRemoved.add(detail);
                }
            }
            for (PickTicketDetail detail : toBeRemoved) {
                this.orderQuantity -= detail.getOrderQtyOfMasterUnit();
            }
            this.getPickTicketDetails().removeAll(toBeRemoved);
        }
        
    }
    
    
    public void removeDetail(List<Long> PlanPickTicketDetailIds) {
        if (this.pickTicketDetails != null && PickTicketStatus.OPEN.equals(this.status)) {
            Set<PickTicketDetail> toBeRemoved = new HashSet<PickTicketDetail>();
            for (PickTicketDetail detail : pickTicketDetails) {
                if (PlanPickTicketDetailIds.contains(detail.getId())) {
                    toBeRemoved.add(detail);
                }
            }
            for (PickTicketDetail detail : toBeRemoved) {
                this.orderQuantity -= detail.getOrderQtyOfMasterUnit();
            }
           
            this.getPickTicketDetails().removeAll(toBeRemoved);
        }
        
    }
    
    /**
     * 发货调整
     * @param pickedRecord 待调整发货记录
     * @param deltaQuantity 差异数量
     * @param description 调整原因
     */
//	public void shippingAdjust(PickedRecord pickedRecord, double deltaQuantity, String description) {
//		this.shippedQuantity -= deltaQuantity;
//		this.allocatedQuantity -= deltaQuantity;
//		this.pickedQuantity -= deltaQuantity;
//        setUserTracking();
//		pickedRecord.getPickTicketDetail().shippingAdjust(pickedRecord, deltaQuantity, description);
//	}

	/**
	 * 发货确认－只能对分配或发运状态的发货单进行发货确认
	 * @param detailConvertFigure 
	 * @param convertFigure 
	 * @param quantiy 单一发货确认的数量
	 */
	public void ship(double quantity){
		if (PickTicketStatus.PICKUP.equals(this.status) 
				|| PickTicketStatus.PICK_ALL.equals(this.status)
				|| PickTicketStatus.SHIP_PART.equals(this.status)) {
			if (quantity > 0) {
				this.shippedQuantity += quantity;
				this.BOLQuantity -= quantity;
				this.packageQuantity -= quantity;
				if (this.shipDate == null) {
					this.shipDate = new Date();
				}
			}
			//所有明细全部发运，检查是否需要自动关闭发货单
			if (this.shippedAllDetails()) {
				this.status = PickTicketStatus.CLOSE;
			} else {
				this.status = PickTicketStatus.SHIP_PART;
			}
            setUserTracking();
		}
		
	}	

	/**
	 * 检查发货单的所有明细是否都已经全部发运
	 * @return true－全部发运，false－部分发运
	 */
	public boolean shippedAllDetails() {
		for (PickTicketDetail pickTicketDetail : this.getPickTicketDetails()) {
			if (pickTicketDetail.getOrderQtyOfMasterUnit() - pickTicketDetail.getShippedQuantity()>0) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 移除掉已全部取消分配的拣货记录
	 * @param removedRecords
	 */
//	public void removePickedRecord(Set<Task> removedRecords) {
//         for(Task record:removedRecords){
//        	 for(PickTicketDetail detail:pickTicketDetails){
//        		 if(detail.getId().equals(record.getPickTicketDetail().getId())){
//        			 detail.getTasks().remove(record);
//        			 break;
//        		 }
//        	 }
//         }
//         setUserTracking();
//	}

	/**
	 * 激活发货单－设置发货单“打开”状态为“生效”
	 * @return true-成功 false－失败
	 */
	public boolean active() {
        if (this.getPickTicketDetails().size()>0 
        		&& PickTicketStatus.OPEN.equals(this.getStatus())) {
            this.setStatus(PickTicketStatus.ACTIVE);
            setUserTracking();
            return true;
        }
		return false;
	}

	/**
	 * 取消激活发货单－设置发货单“生效”状态为“打开”
	 * @return true-成功 false－失败
	 */
	public boolean inactive() {
        if (PickTicketStatus.ACTIVE.equals(this.getStatus())) {
            this.setStatus(PickTicketStatus.OPEN);
            setUserTracking();
            return true;
        }
		return false;
	}

	/**
	 * 取消发货单－设置发货单状态为“取消”
	 * @return true-成功 false－失败
	 */
	public boolean cancel() {
        if (PickTicketStatus.OPEN.equals(this.getStatus())) {
            this.setStatus(PickTicketStatus.CANCEL);
            setUserTracking();
            return true;
        }
		return false;
	}

	/**
	 * 关闭发货单－设置发货单状态为“关闭”
	 * @return true-成功 false－失败
	 */
	public boolean close() {
        if (PickTicketStatus.SHIP_PART.equals(this.getStatus()) || PickTicketStatus.SHIP_ALL.equals(this.getStatus())) {
            this.setStatus(PickTicketStatus.CLOSE);
            setUserTracking();
            return true;
        }else //如果是关联的批拣单，在没有分配商品时，可以在ACTIVE状态下关闭
        	if(PickTicketStatus.ACTIVE.equals(this.getStatus()) 
        		&& this.getAllocatedQuantity()<=0){
            this.setStatus(PickTicketStatus.CLOSE);
            setUserTracking();
            return true;        	
        }
        
		return false;
	}

	@Override
	public List<AbstractMoveDocDetail> getAbstractMoveDocDetails() {
		List<AbstractMoveDocDetail> details = new ArrayList<AbstractMoveDocDetail>();
		for(PickTicketDetail detail :this.pickTicketDetails){
			details.add(detail);
		}
        return details;

	}

	public String getWaveCode() {
		return waveCode;
	}

	public void setWaveCode(String waveCode) {
		this.waveCode = waveCode;
	}

	/**
     * 取消拣货
     * @param quantity
     */
	public void pickBack(double pickedQty){
		this.allocatedQuantity -= pickedQty;
		this.pickedQuantity -= pickedQty;
		if (this.pickedQuantity <= 0) {
			if (this.allocatedQuantity > 0) {
				this.setStatus(PickTicketStatus.ALLOCATE);
			} else {
				this.setStatus(PickTicketStatus.OPEN);
			}
		} else {
			this.setStatus(PickTicketStatus.PICKUP);
		}
		this.setMasterBOL(null);
//		setUserTracking();
	}

	/**
	 * 发货单预分配
	 * 更新发货单状态为'预分配'，并修改预分配数量
	 * @param quantity 预分配数量(MU)
	 */
	public void preAllocate(Double quantity) {
		if (PickTicketStatus.ACTIVE.equals(this.status) || PickTicketStatus.SHIP_PART.equals(this.status)) {
			//this.setStatus(PickTicketStatus.PREALLOCATE);
			this.setStatus(PickTicketStatus.ACTIVE);
		}
		this.preAllocatedQuantity += quantity;
	}

	/**
	 * 发货单取消预分配
	 * 减少预分配数量，如果预分配数量为0，设置发货单状态为'生效'
	 * @param quantity
	 */
	public void unPreAllocate(Double quantity) {
		this.preAllocatedQuantity -= quantity;
		if (this.preAllocatedQuantity == 0) {
			this.setStatus(PickTicketStatus.ACTIVE);
		}
	}

	public PickTicketDetail getPickTicketDetail(Long detailId) {
		for (PickTicketDetail detail : this.getPickTicketDetails()) {
			if (detail.getId().equals(detailId)) {
				return detail;
			}
		}
		return null;
	}
	

	public void autoPack(TaskLog taskLog) {
		this.BOLQuantity += taskLog.getMovedQuantity()*taskLog.getPackageUnit().getConvertFigure();
		this.packageQuantity += taskLog.getMovedQuantity()*taskLog.getPackageUnit().getConvertFigure();
	}
	
	public void manualAutoPack(double inputQty,PackageUnit pkg) {
		this.BOLQuantity += inputQty*pkg.getConvertFigure();
		this.packageQuantity += inputQty*pkg.getConvertFigure();
	}

	public boolean isCrossStocking() {
		return crossStocking;
	}

	public void setCrossStocking(boolean crossStocking) {
		this.crossStocking = crossStocking;
	}

	public void allocateCross(double quantity) {
		this.preAllocatedQuantity += quantity;
		this.allocatedQuantity += quantity;
		if (PickTicketStatus.ACTIVE.equals(this.status)
				|| PickTicketStatus.PICKUP.equals(this.status)
				|| PickTicketStatus.SHIP_PART.equals(this.status)) {
			this.setStatus(PickTicketStatus.ALLOCATE);
		}
	}
	//得到发货单总体积
	public double getTotalVolumn(){
		double volumn = 0.0;
		for(PickTicketDetail detail:this.getPickTicketDetails()){
			volumn+=detail.getOrderQuantity()*detail.getPackageUnit().getVolume();
		}
		return volumn;
	}
//	得到发货单总重量
	public double getTotalWeight(){
		double weight = 0.0;
		for(PickTicketDetail detail:this.getPickTicketDetails()){
			weight+=detail.getOrderQuantity()*detail.getPackageUnit().getWeight();
		}
		return weight;
	}
//	得到发货单待拣货体积
	public double getPickVolumn(){
		double volumn = 0.0;
		for(PickTicketDetail detail:this.getPickTicketDetails()){
			volumn+=(detail.getAllocatedQuantity()-detail.getPickedQuantity())*detail.getItem().getMinPackageUnit().getVolume();
		}
		return volumn;
	}
//	得到发货单待拣货重量
	public double getPickWeight(){
		double weight = 0.0;
		for(PickTicketDetail detail:this.getPickTicketDetails()){
			weight+=(detail.getAllocatedQuantity()-detail.getPickedQuantity())*detail.getItem().getMinPackageUnit().getWeight();
		}
		return weight;
	}
	
	/**
	 * 移除和附件的关联关系
	 * 
	 * @author  dev
	 */
	public void removeFiles(SignFile signFile) {
		this.getFiles().remove(signFile);
	}
}
