/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* Copyright (C) 2003-2007 e-Evolution,SC. All Rights Reserved. *
* Contributor(s): Victor Perez www.e-evolution.com *
*****************************************************************************/
package org.eevolution.model;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Properties;
import org.compiere.model.MAttributeSet;
import org.compiere.model.MCharge;
import org.compiere.model.MLocator;
import org.compiere.model.MProduct;
import org.compiere.model.MStorageOnHand;
import org.compiere.model.MUOM;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
/**
* Order Line Model.
*
* MDDOrderLine ol = new MDDOrderLine(m_order);
ol.setM_Product_ID(wbl.getM_Product_ID());
ol.setQtyOrdered(wbl.getQuantity());
ol.setPriceActual(wbl.getPrice());
ol.setTax();
ol.saveEx();
*
* @author Jorg Janke
* @version $Id: MOrderLine.java,v 1.6 2006/10/02 05:18:39 jjanke Exp $
*/
public class MDDOrderLine extends X_DD_OrderLine
{
/**
*
*/
private static final long serialVersionUID = -8878804332001384969L;
/**
* Get Order Unreserved Qty
* @param ctx context
* @param M_Locator_ID wh
* @param M_Product_ID product
* @param M_AttributeSetInstance_ID asi
* @param excludeDD_OrderLine_ID exclude DD_OrderLine_ID
* @return Unreserved Qty
*/
public static BigDecimal getNotReserved (Properties ctx, int M_Locator_ID,
int M_Product_ID, int M_AttributeSetInstance_ID, int excludeDD_OrderLine_ID)
{
ArrayList params = new ArrayList();
params.add(M_Locator_ID);
params.add(M_Product_ID);
params.add(excludeDD_OrderLine_ID);
String sql = "SELECT SUM(QtyOrdered-QtyDelivered-QtyReserved) "
+ "FROM DD_OrderLine ol"
+ " INNER JOIN DD_Order o ON (ol.DD_Order_ID=o.DD_Order_ID) "
+ "WHERE ol.M_Locator_ID=?" // #1
+ " AND M_Product_ID=?" // #2
+ " AND o.IsSOTrx='N' AND o.DocStatus='DR'"
+ " AND QtyOrdered-QtyDelivered-QtyReserved<>0"
+ " AND ol.DD_OrderLine_ID<>?";
if (M_AttributeSetInstance_ID != 0)
{
sql += " AND M_AttributeSetInstance_ID=?";
params.add(M_AttributeSetInstance_ID);
}
return DB.getSQLValueBD(null, sql.toString(), params);
} // getNotReserved
/** Logger */
@SuppressWarnings("unused")
private static CLogger s_log = CLogger.getCLogger (MDDOrderLine.class);
/**
* UUID based Constructor
* @param ctx Context
* @param DD_OrderLine_UU UUID key
* @param trxName Transaction
*/
public MDDOrderLine(Properties ctx, String DD_OrderLine_UU, String trxName) {
super(ctx, DD_OrderLine_UU, trxName);
if (Util.isEmpty(DD_OrderLine_UU))
setInitialDefaults();
}
/**************************************************************************
* Default Constructor
* @param ctx context
* @param C_OrderLine_ID order line to load
* @param trxName trx name
*/
public MDDOrderLine (Properties ctx, int C_OrderLine_ID, String trxName)
{
super (ctx, C_OrderLine_ID, trxName);
if (C_OrderLine_ID == 0)
setInitialDefaults();
} // MDDOrderLine
/**
* Set the initial defaults for a new record
*/
private void setInitialDefaults() {
// setC_Order_ID (0);
// setLine (0);
// setM_Warehouse_ID (0); // @M_Warehouse_ID@
// setC_BPartner_ID(0);
// setC_BPartner_Location_ID (0); // @C_BPartner_Location_ID@
// setC_Currency_ID (0); // @C_Currency_ID@
// setDateOrdered (new Timestamp(System.currentTimeMillis())); // @DateOrdered@
//
// setC_Tax_ID (0);
// setC_UOM_ID (0);
//
setFreightAmt (Env.ZERO);
setLineNetAmt (Env.ZERO);
//
setM_AttributeSetInstance_ID(0);
//
setQtyEntered (Env.ZERO);
setQtyInTransit (Env.ZERO);
setConfirmedQty(Env.ZERO);
setTargetQty(Env.ZERO);
setPickedQty(Env.ZERO);
setQtyOrdered (Env.ZERO); // 1
setQtyDelivered (Env.ZERO);
setQtyReserved (Env.ZERO);
//
setIsDescription (false); // N
setProcessed (false);
setLine (0);
}
/**
* Parent Constructor.
ol.setM_Product_ID(wbl.getM_Product_ID());
ol.setQtyOrdered(wbl.getQuantity());
ol.setPrice();
ol.setPriceActual(wbl.getPrice());
ol.setTax();
ol.saveEx();
* @param order parent order
*/
public MDDOrderLine (MDDOrder order)
{
this (order.getCtx(), 0, order.get_TrxName());
if (order.get_ID() == 0)
throw new IllegalArgumentException("Header not saved");
setDD_Order_ID (order.getDD_Order_ID()); // parent
setOrder(order);
} // MDDOrderLine
/**
* Load Constructor
* @param ctx context
* @param rs result set record
* @param trxName transaction
*/
public MDDOrderLine (Properties ctx, ResultSet rs, String trxName)
{
super(ctx, rs, trxName);
} // MDDOrderLine
public MDDOrderLine(Properties ctx, int DD_OrderLine_ID, String trxName, String... virtualColumns) {
super(ctx, DD_OrderLine_ID, trxName, virtualColumns);
}
private int m_M_PriceList_ID = 0;
//
private boolean m_IsSOTrx = true;
/** Cached Currency Precision */
//private Integer m_precision = null;
/** Product */
private MProduct m_product = null;
/** Parent */
private MDDOrder m_parent = null;
/**
* Set Defaults from Order.
* Does not set Parent !!
* @param order order
*/
public void setOrder (MDDOrder order)
{
setClientOrg(order);
/*setC_BPartner_ID(order.getC_BPartner_ID());
setC_BPartner_Location_ID(order.getC_BPartner_Location_ID());*/
//setM_Warehouse_ID(order.getM_Warehouse_ID());
setDateOrdered(order.getDateOrdered());
setDatePromised(order.getDatePromised());
//
setHeaderInfo(order); // sets m_order
// Don't set Activity, etc as they are overwrites
} // setOrder
/**
* Set Header Info
* @param order order
*/
public void setHeaderInfo (MDDOrder order)
{
m_parent = order;
m_IsSOTrx = order.isSOTrx();
} // setHeaderInfo
/**
* Get Parent
* @return parent
*/
public MDDOrder getParent()
{
if (m_parent == null)
m_parent = new MDDOrder(getCtx(), getDD_Order_ID(), get_TrxName());
return m_parent;
} // getParent
/**
* Set Product
* @param product product
*/
public void setProduct (MProduct product)
{
m_product = product;
if (m_product != null)
{
setM_Product_ID(m_product.getM_Product_ID());
setC_UOM_ID (m_product.getC_UOM_ID());
}
else
{
setM_Product_ID(0);
set_ValueNoCheck ("C_UOM_ID", null);
}
setM_AttributeSetInstance_ID(0);
} // setProduct
/**
* Set M_Product_ID
* @param M_Product_ID product
* @param setUOM set also UOM
*/
public void setM_Product_ID (int M_Product_ID, boolean setUOM)
{
if (setUOM)
setProduct(MProduct.get(getCtx(), M_Product_ID));
else
super.setM_Product_ID (M_Product_ID);
setM_AttributeSetInstance_ID(0);
} // setM_Product_ID
/**
* Set Product and UOM
* @param M_Product_ID product
* @param C_UOM_ID uom
*/
public void setM_Product_ID (int M_Product_ID, int C_UOM_ID)
{
super.setM_Product_ID (M_Product_ID);
if (C_UOM_ID != 0)
super.setC_UOM_ID(C_UOM_ID);
setM_AttributeSetInstance_ID(0);
} // setM_Product_ID
/**
* Get Product
* @return product or null
*/
public MProduct getProduct()
{
if (m_product == null && getM_Product_ID() != 0)
m_product = MProduct.getCopy(getCtx(), getM_Product_ID(), get_TrxName());
return m_product;
} // getProduct
/**
* Set M_AttributeSetInstance_ID
* @param M_AttributeSetInstance_ID id
*/
public void setM_AttributeSetInstance_ID (int M_AttributeSetInstance_ID)
{
if (M_AttributeSetInstance_ID == 0) // 0 is valid ID
set_Value("M_AttributeSetInstance_ID", Integer.valueOf(0));
else
super.setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
} // setM_AttributeSetInstance_ID
/**
* Set Warehouse
* @param M_Warehouse_ID warehouse
*/
/*public void setM_Warehouse_ID (int M_Warehouse_ID)
{
if (getM_Warehouse_ID() > 0
&& getM_Warehouse_ID() != M_Warehouse_ID
&& !canChangeWarehouse())
log.severe("Ignored - Already Delivered/Invoiced/Reserved");
else
super.setM_Warehouse_ID (M_Warehouse_ID);
} // setM_Warehouse_ID
*/
/**
* Can Change Warehouse
* @return true if warehouse can be changed
*/
public boolean canChangeWarehouse()
{
if (getQtyDelivered().signum() != 0)
{
log.saveError("Error", Msg.translate(getCtx(), "QtyDelivered") + "=" + getQtyDelivered());
return false;
}
if (getQtyReserved().signum() != 0)
{
log.saveError("Error", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved());
return false;
}
// We can change
return true;
} // canChangeWarehouse
/**
* Get C_Project_ID
* @return project
*/
public int getC_Project_ID()
{
int ii = super.getC_Project_ID ();
if (ii == 0)
ii = getParent().getC_Project_ID();
return ii;
} // getC_Project_ID
/**
* Get C_Activity_ID
* @return Activity
*/
public int getC_Activity_ID()
{
int ii = super.getC_Activity_ID ();
if (ii == 0)
ii = getParent().getC_Activity_ID();
return ii;
} // getC_Activity_ID
/**
* Get C_Campaign_ID
* @return Campaign
*/
public int getC_Campaign_ID()
{
int ii = super.getC_Campaign_ID ();
if (ii == 0)
ii = getParent().getC_Campaign_ID();
return ii;
} // getC_Campaign_ID
/**
* Get User2_ID
* @return User2
*/
public int getUser1_ID ()
{
int ii = super.getUser1_ID ();
if (ii == 0)
ii = getParent().getUser1_ID();
return ii;
} // getUser1_ID
/**
* Get User2_ID
* @return User2
*/
public int getUser2_ID ()
{
int ii = super.getUser2_ID ();
if (ii == 0)
ii = getParent().getUser2_ID();
return ii;
} // getUser2_ID
/**
* Get AD_OrgTrx_ID
* @return trx org
*/
public int getAD_OrgTrx_ID()
{
int ii = super.getAD_OrgTrx_ID();
if (ii == 0)
ii = getParent().getAD_OrgTrx_ID();
return ii;
} // getAD_OrgTrx_ID
/**************************************************************************
* String Representation
* @return info
*/
public String toString ()
{
StringBuilder sb = new StringBuilder ("MDDOrderLine[")
.append(get_ID()).append(",Line=").append(getLine())
.append(",Ordered=").append(getQtyOrdered())
.append(",Delivered=").append(getQtyDelivered())
.append(",Reserved=").append(getQtyReserved())
.append ("]");
return sb.toString ();
} // toString
/**
* Add to Description
* @param description text
*/
public void addDescription (String description)
{
String desc = getDescription();
if (desc == null)
setDescription(description);
else
setDescription(desc + " | " + description);
} // addDescription
/**
* Get Description Text.
* For jsp access (vs. isDescription)
* @return description
*/
public String getDescriptionText()
{
return super.getDescription();
} // getDescriptionText
/**
* Get Name
* @return get the name of the line (from Product)
*/
public String getName()
{
getProduct();
if (m_product != null)
return m_product.getName();
if (getC_Charge_ID() != 0)
{
MCharge charge = MCharge.get(getCtx(), getC_Charge_ID());
return charge.getName();
}
return "";
} // getName
/**
* Set C_Charge_ID
* @param C_Charge_ID charge
*/
public void setC_Charge_ID (int C_Charge_ID)
{
super.setC_Charge_ID (C_Charge_ID);
if (C_Charge_ID > 0)
set_ValueNoCheck ("C_UOM_ID", null);
} // setC_Charge_ID
/**
* Set Qty Entered/Ordered.
* Use this Method if the Line UOM is the Product UOM
* @param Qty QtyOrdered/Entered
*/
public void setQty (BigDecimal Qty)
{
super.setQtyEntered (Qty);
super.setQtyOrdered (getQtyEntered());
} // setQty
/**
* Set Qty Entered - enforce entered UOM
* @param QtyEntered
*/
public void setQtyEntered (BigDecimal QtyEntered)
{
if (QtyEntered != null && getC_UOM_ID() != 0)
{
int precision = MUOM.getPrecision(getCtx(), getC_UOM_ID());
QtyEntered = QtyEntered.setScale(precision, RoundingMode.HALF_UP);
}
super.setQtyEntered (QtyEntered);
} // setQtyEntered
/**
* Set Qty Ordered - enforce Product UOM
* @param QtyOrdered
*/
public void setQtyOrdered (BigDecimal QtyOrdered)
{
MProduct product = getProduct();
if (QtyOrdered != null && product != null)
{
int precision = product.getUOMPrecision();
QtyOrdered = QtyOrdered.setScale(precision, RoundingMode.HALF_UP);
}
super.setQtyOrdered(QtyOrdered);
} // setQtyOrdered
@Override
protected boolean beforeSave (boolean newRecord)
{
if (newRecord && getParent().isProcessed()) {
log.saveError("ParentComplete", Msg.translate(getCtx(), "DD_Order_ID"));
return false;
}
// Get Defaults from Parent
if (m_M_PriceList_ID == 0)
setHeaderInfo(getParent());
// Validate Product/Warehouse/Locator Change
if (!newRecord
&& (is_ValueChanged("M_Product_ID") || is_ValueChanged("M_Locator_ID") || is_ValueChanged("M_LocatorTo_ID")))
{
if (!canChangeWarehouse())
return false;
}
// Charge line, set M_Product_ID to 0
if (getC_Charge_ID() != 0 && getM_Product_ID() != 0)
setM_Product_ID(0);
// No Product, set M_AttributeSetInstance_ID to 0
if (getM_Product_ID() == 0)
setM_AttributeSetInstance_ID(0);
// Default UOM
if (getC_UOM_ID() == 0
&& (getM_Product_ID() != 0
|| getC_Charge_ID() != 0))
{
int C_UOM_ID = MUOM.getDefault_UOM_ID(getCtx());
if (C_UOM_ID > 0)
setC_UOM_ID (C_UOM_ID);
}
// Enforce Qty Precision
if (newRecord || is_ValueChanged("QtyEntered"))
setQtyEntered(getQtyEntered());
if (newRecord || is_ValueChanged("QtyOrdered"))
setQtyOrdered(getQtyOrdered());
// Validate on hand for product line with ASI
if (m_IsSOTrx
&& getM_AttributeSetInstance_ID() != 0
&& (newRecord || is_ValueChanged("M_Product_ID")
|| is_ValueChanged("M_AttributeSetInstance_ID")
|| is_ValueChanged("M_Warehouse_ID")))
{
MProduct product = getProduct();
if (product.isStocked())
{
int M_AttributeSet_ID = product.getM_AttributeSet_ID();
boolean isInstance = M_AttributeSet_ID != 0;
if (isInstance)
{
MAttributeSet mas = MAttributeSet.get(getCtx(), M_AttributeSet_ID);
isInstance = mas.isInstanceAttribute();
}
// Validate on hand >= QtyOrdered if product has instance attribute
if (isInstance)
{
MLocator locator_from = MLocator.get(getCtx(), getM_Locator_ID());
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
locator_from.getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(),
null, true, false, 0, get_TrxName());
BigDecimal qty = Env.ZERO;
for (int i = 0; i < storages.length; i++)
{
if (storages[i].getM_AttributeSetInstance_ID() == getM_AttributeSetInstance_ID())
qty = qty.add(storages[i].getQtyOnHand());
}
if (getQtyOrdered().compareTo(qty) > 0)
{
log.warning("Qty - Stock=" + qty + ", Ordered=" + getQtyOrdered());
log.saveError("QtyInsufficient", "=" + qty);
return false;
}
}
} // stocked
} // SO instance
// FreightAmt Not used
if (Env.ZERO.compareTo(getFreightAmt()) != 0)
setFreightAmt(Env.ZERO);
// Set Line No
if (getLine() == 0)
{
String sql = "SELECT COALESCE(MAX(Line),0)+10 FROM C_OrderLine WHERE C_Order_ID=?";
int ii = DB.getSQLValue (get_TrxName(), sql, getDD_Order_ID());
setLine (ii);
}
return true;
} // beforeSave
@Override
protected boolean beforeDelete ()
{
// Can't delete if QtyDelivered is not 0
if (Env.ZERO.compareTo(getQtyDelivered()) != 0)
{
log.saveError("DeleteError", Msg.translate(getCtx(), "QtyDelivered") + "=" + getQtyDelivered());
return false;
}
// Can't delete if QtyReserved is not 0
if (Env.ZERO.compareTo(getQtyReserved()) != 0)
{
// For PO should be On Order
log.saveError("DeleteError", Msg.translate(getCtx(), "QtyReserved") + "=" + getQtyReserved());
return false;
}
return true;
} // beforeDelete
/**
* Quantity To Deliver
* @return Quantity To Deliver
*/
public BigDecimal getQtyToDeliver()
{
return getQtyOrdered().subtract(getQtyInTransit()).subtract(getQtyDelivered());
}
} // MDDOrderLine