IDEMPIERE-385 Resolve M_Storage locking and data consistency / Code refinements
This commit is contained in:
parent
d74f7933ba
commit
c93620b3c9
|
@ -118,15 +118,14 @@ public class CalloutMovement extends CalloutEngine
|
||||||
if (MovementQty == null)
|
if (MovementQty == null)
|
||||||
MovementQty = (BigDecimal) mTab.getValue("MovementQty");
|
MovementQty = (BigDecimal) mTab.getValue("MovementQty");
|
||||||
int M_Locator_ID = Env.getContextAsInt(ctx, WindowNo, "M_Locator_ID");
|
int M_Locator_ID = Env.getContextAsInt(ctx, WindowNo, "M_Locator_ID");
|
||||||
|
|
||||||
// If no locator, don't check anything and assume is ok
|
// If no locator, don't check anything and assume is ok
|
||||||
if (M_Locator_ID <= 0)
|
if (M_Locator_ID <= 0)
|
||||||
return;
|
return;
|
||||||
//@win - IDEMPIERE-385
|
|
||||||
int M_Warehouse_ID = DB.getSQLValue(null, "SELECT M_Warehouse_ID FROM M_Locator WHERE M_Locator_ID=?", M_Locator_ID);
|
|
||||||
//
|
|
||||||
int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID");
|
int M_AttributeSetInstance_ID = Env.getContextAsInt(ctx, WindowNo, "M_AttributeSetInstance_ID");
|
||||||
BigDecimal available = MStorageReservation.getQtyAvailable(M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, null);
|
BigDecimal available = Env.ZERO;
|
||||||
|
MStorageOnHand oh = MStorageOnHand.get(ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, null);
|
||||||
|
if (oh != null)
|
||||||
|
available = oh.getQtyOnHand();
|
||||||
if (available == null)
|
if (available == null)
|
||||||
available = Env.ZERO;
|
available = Env.ZERO;
|
||||||
if (available.signum() == 0)
|
if (available.signum() == 0)
|
||||||
|
|
|
@ -150,6 +150,16 @@ public class OrgOwnership extends SvrProcess
|
||||||
no = DB.executeUpdate(sql.toString(), get_TrxName());
|
no = DB.executeUpdate(sql.toString(), get_TrxName());
|
||||||
addLog (0,null, new BigDecimal(no), Msg.translate(getCtx(), "Storage"));
|
addLog (0,null, new BigDecimal(no), Msg.translate(getCtx(), "Storage"));
|
||||||
|
|
||||||
|
// Set Storage Reservation
|
||||||
|
sql = new StringBuilder();
|
||||||
|
sql.append("UPDATE M_StorageReservation s ")
|
||||||
|
.append("SET AD_Org_ID=").append(p_AD_Org_ID)
|
||||||
|
.append(" WHERE M_Warehouse_ID=").append(p_M_Warehouse_ID)
|
||||||
|
.append(" AND AD_Client_ID=").append(getAD_Client_ID())
|
||||||
|
.append(" AND AD_Org_ID<>").append(p_AD_Org_ID);
|
||||||
|
no = DB.executeUpdate(sql.toString(), get_TrxName());
|
||||||
|
addLog (0,null, new BigDecimal(no), Msg.translate(getCtx(), "StorageReservation"));
|
||||||
|
|
||||||
return "";
|
return "";
|
||||||
} // warehouseOwnership
|
} // warehouseOwnership
|
||||||
|
|
||||||
|
|
|
@ -251,10 +251,10 @@ public class ReplenishReport extends SvrProcess
|
||||||
sql = new StringBuilder("UPDATE T_Replenish t SET ");
|
sql = new StringBuilder("UPDATE T_Replenish t SET ");
|
||||||
sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_StorageOnHand s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_StorageOnHand s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
||||||
sql.append("QtyReserved = (SELECT COALESCE(SUM(QtyReserved),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyReserved = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID),");
|
||||||
sql.append("QtyOrdered = (SELECT COALESCE(SUM(QtyOrdered),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyOrdered = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID)");
|
sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID)");
|
||||||
if (p_C_DocType_ID != 0)
|
if (p_C_DocType_ID != 0)
|
||||||
sql.append(", C_DocType_ID=").append(p_C_DocType_ID);
|
sql.append(", C_DocType_ID=").append(p_C_DocType_ID);
|
||||||
sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID());
|
sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID());
|
||||||
|
@ -535,9 +535,8 @@ public class ReplenishReport extends SvrProcess
|
||||||
MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID());
|
MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID());
|
||||||
String MMPolicy = product.getMMPolicy();
|
String MMPolicy = product.getMMPolicy();
|
||||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0,
|
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null,
|
||||||
true, null,
|
MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName());
|
||||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
|
|
||||||
//
|
//
|
||||||
BigDecimal target = replenish.getQtyToOrder();
|
BigDecimal target = replenish.getQtyToOrder();
|
||||||
for (int j = 0; j < storages.length; j++)
|
for (int j = 0; j < storages.length; j++)
|
||||||
|
|
|
@ -269,12 +269,12 @@ public class ReplenishReportProduction extends SvrProcess
|
||||||
}
|
}
|
||||||
|
|
||||||
sql = new StringBuilder("UPDATE T_Replenish t SET ");
|
sql = new StringBuilder("UPDATE T_Replenish t SET ");
|
||||||
sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_Storage s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyOnHand = (SELECT COALESCE(SUM(QtyOnHand),0) FROM M_StorageOnHand s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
sql.append(" AND l.M_Locator_ID=s.M_Locator_ID AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
||||||
sql.append("QtyReserved = (SELECT COALESCE(SUM(QtyReserved),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyReserved = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID),");
|
sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID),");
|
||||||
sql.append("QtyOrdered = (SELECT COALESCE(SUM(QtyOrdered),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
sql.append("QtyOrdered = (SELECT COALESCE(SUM(Qty),0) FROM M_StorageReservation s WHERE t.M_Product_ID=s.M_Product_ID");
|
||||||
sql.append(" AND l.M_Warehouse_ID=t.M_Warehouse_ID)");
|
sql.append(" AND t.M_Warehouse_ID=s.M_Warehouse_ID)");
|
||||||
if (p_C_DocType_ID != 0)
|
if (p_C_DocType_ID != 0)
|
||||||
sql.append(", C_DocType_ID=").append(p_C_DocType_ID);
|
sql.append(", C_DocType_ID=").append(p_C_DocType_ID);
|
||||||
sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID());
|
sql.append(" WHERE AD_PInstance_ID=").append(getAD_PInstance_ID());
|
||||||
|
@ -571,9 +571,8 @@ public class ReplenishReportProduction extends SvrProcess
|
||||||
MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID());
|
MProduct product = MProduct.get(getCtx(), replenish.getM_Product_ID());
|
||||||
String MMPolicy = product.getMMPolicy();
|
String MMPolicy = product.getMMPolicy();
|
||||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0,
|
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null,
|
||||||
true, null,
|
MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName());
|
||||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
|
|
||||||
//
|
//
|
||||||
BigDecimal target = replenish.getQtyToOrder();
|
BigDecimal target = replenish.getQtyToOrder();
|
||||||
for (int j = 0; j < storages.length; j++)
|
for (int j = 0; j < storages.length; j++)
|
||||||
|
|
|
@ -69,11 +69,18 @@ public class StorageCleanup extends SvrProcess
|
||||||
log.info("");
|
log.info("");
|
||||||
// Clean up empty Storage
|
// Clean up empty Storage
|
||||||
String sql = "DELETE FROM M_StorageOnHand "
|
String sql = "DELETE FROM M_StorageOnHand "
|
||||||
+ "WHERE QtyOnHand = 0 AND QtyReserved = 0 AND QtyOrdered = 0"
|
+ "WHERE QtyOnHand = 0"
|
||||||
+ " AND Created < SysDate-3";
|
+ " AND Created < SysDate-3";
|
||||||
int no = DB.executeUpdate(sql, get_TrxName());
|
int no = DB.executeUpdate(sql, get_TrxName());
|
||||||
log.info("Delete Empty #" + no);
|
log.info("Delete Empty #" + no);
|
||||||
|
|
||||||
|
// Clean up empty Reservation Storage
|
||||||
|
sql = "DELETE FROM M_StorageReservation "
|
||||||
|
+ "WHERE Qty = 0"
|
||||||
|
+ " AND Created < SysDate-3";
|
||||||
|
no = DB.executeUpdate(sql, get_TrxName());
|
||||||
|
log.info("Delete Empty #" + no);
|
||||||
|
|
||||||
//
|
//
|
||||||
sql = "SELECT * "
|
sql = "SELECT * "
|
||||||
+ "FROM M_StorageOnHand s "
|
+ "FROM M_StorageOnHand s "
|
||||||
|
|
|
@ -1361,22 +1361,60 @@ public class MInOut extends X_M_InOut implements DocAction
|
||||||
get_TrxName()))
|
get_TrxName()))
|
||||||
{
|
{
|
||||||
String lastError = CLogger.retrieveErrorString("");
|
String lastError = CLogger.retrieveErrorString("");
|
||||||
m_processMsg = "Cannot correct Inventory (MA) - " + lastError;
|
m_processMsg = "Cannot correct Inventory OnHand (MA) - " + lastError;
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
|
if (sameWarehouse && reservedDiff.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
reservedDiff,
|
||||||
|
true,
|
||||||
|
get_TrxName()))
|
||||||
|
{
|
||||||
|
String lastError = CLogger.retrieveErrorString("");
|
||||||
|
m_processMsg = "Cannot correct Inventory Reserved (MA) - " + lastError;
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (sameWarehouse && orderedDiff.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
orderedDiff,
|
||||||
|
false,
|
||||||
|
get_TrxName()))
|
||||||
|
{
|
||||||
|
String lastError = CLogger.retrieveErrorString("");
|
||||||
|
m_processMsg = "Cannot correct Inventory Ordered (MA) - " + lastError;
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!sameWarehouse) {
|
if (!sameWarehouse) {
|
||||||
//correct qtyOrdered in warehouse of order
|
//correct qtyOrdered in warehouse of order
|
||||||
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
||||||
if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(),
|
if (reservedDiff.signum() != 0) {
|
||||||
wh.getDefaultLocator().getM_Locator_ID(),
|
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||||
sLine.getM_Product_ID(),
|
sLine.getM_Product_ID(),
|
||||||
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
Env.ZERO, get_TrxName()))
|
reservedDiff, true, get_TrxName()))
|
||||||
{
|
{
|
||||||
m_processMsg = "Cannot correct Inventory (MA) in order warehouse";
|
m_processMsg = "Cannot correct Inventory Reserved (MA) in order warehouse";
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (orderedDiff.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
orderedDiff, false, get_TrxName()))
|
||||||
|
{
|
||||||
|
m_processMsg = "Cannot correct Inventory Ordered (MA) in order warehouse";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
// Create Transaction
|
// Create Transaction
|
||||||
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(),
|
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(),
|
||||||
MovementType, sLine.getM_Locator_ID(),
|
MovementType, sLine.getM_Locator_ID(),
|
||||||
|
@ -1403,22 +1441,53 @@ public class MInOut extends X_M_InOut implements DocAction
|
||||||
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
Qty, get_TrxName()))
|
Qty, get_TrxName()))
|
||||||
{
|
{
|
||||||
m_processMsg = "Cannot correct Inventory";
|
m_processMsg = "Cannot correct Inventory OnHand";
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
|
if (reservedDiff.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
reservedDiff, true, get_TrxName()))
|
||||||
|
{
|
||||||
|
m_processMsg = "Cannot correct Inventory Reserved";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (orderedDiff.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
orderedDiff, false, get_TrxName()))
|
||||||
|
{
|
||||||
|
m_processMsg = "Cannot correct Inventory Ordered";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!sameWarehouse) {
|
if (!sameWarehouse) {
|
||||||
//correct qtyOrdered in warehouse of order
|
//correct qtyOrdered in warehouse of order
|
||||||
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
||||||
if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(),
|
if (QtySO.signum() != 0) {
|
||||||
wh.getDefaultLocator().getM_Locator_ID(),
|
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||||
sLine.getM_Product_ID(),
|
sLine.getM_Product_ID(),
|
||||||
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
Env.ZERO, get_TrxName()))
|
QtySO.negate(), true, get_TrxName()))
|
||||||
{
|
{
|
||||||
m_processMsg = "Cannot correct Inventory";
|
m_processMsg = "Cannot correct Inventory Reserved";
|
||||||
return DocAction.STATUS_Invalid;
|
return DocAction.STATUS_Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (QtyPO.signum() != 0) {
|
||||||
|
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||||
|
sLine.getM_Product_ID(),
|
||||||
|
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
|
||||||
|
QtyPO.negate(), false, get_TrxName()))
|
||||||
|
{
|
||||||
|
m_processMsg = "Cannot correct Inventory Ordered";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
// FallBack: Create Transaction
|
// FallBack: Create Transaction
|
||||||
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(),
|
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_ID(),
|
||||||
MovementType, sLine.getM_Locator_ID(),
|
MovementType, sLine.getM_Locator_ID(),
|
||||||
|
|
|
@ -332,7 +332,7 @@ public final class MLocatorLookup extends Lookup implements Serializable
|
||||||
sql.append(" AND (IsDefault='Y' ") // Default Locator
|
sql.append(" AND (IsDefault='Y' ") // Default Locator
|
||||||
.append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator
|
.append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator
|
||||||
.append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)")
|
.append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)")
|
||||||
.append("OR EXISTS (SELECT * FROM M_StorageOnHand s ") // Storage Locator
|
.append("OR EXISTS (SELECT * FROM M_Storage s ") // Storage Locator
|
||||||
.append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))");
|
.append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))");
|
||||||
sql.append(" ORDER BY ");
|
sql.append(" ORDER BY ");
|
||||||
if (local_only_warehouse_id == 0)
|
if (local_only_warehouse_id == 0)
|
||||||
|
|
|
@ -1566,38 +1566,13 @@ public class MOrder extends X_C_Order implements DocAction
|
||||||
{
|
{
|
||||||
if (product.isStocked())
|
if (product.isStocked())
|
||||||
{
|
{
|
||||||
BigDecimal ordered = isSOTrx ? Env.ZERO : difference;
|
// Update Reservation Storage
|
||||||
BigDecimal reserved = isSOTrx ? difference : Env.ZERO;
|
if (!MStorageReservation.add(getCtx(), line.getM_Warehouse_ID(),
|
||||||
int M_Locator_ID = 0;
|
|
||||||
// Get Locator to reserve
|
|
||||||
if (line.getM_AttributeSetInstance_ID() != 0) // Get existing Location
|
|
||||||
M_Locator_ID = MStorageOnHand.getM_Locator_ID (line.getM_Warehouse_ID(),
|
|
||||||
line.getM_Product_ID(), line.getM_AttributeSetInstance_ID(),
|
|
||||||
ordered, get_TrxName());
|
|
||||||
// Get default Location
|
|
||||||
if (M_Locator_ID == 0)
|
|
||||||
{
|
|
||||||
// try to take default locator for product first
|
|
||||||
// if it is from the selected warehouse
|
|
||||||
MWarehouse wh = MWarehouse.get(getCtx(), line.getM_Warehouse_ID());
|
|
||||||
M_Locator_ID = product.getM_Locator_ID();
|
|
||||||
if (M_Locator_ID!=0) {
|
|
||||||
MLocator locator = new MLocator(getCtx(), product.getM_Locator_ID(), get_TrxName());
|
|
||||||
//product has default locator defined but is not from the order warehouse
|
|
||||||
if(locator.getM_Warehouse_ID()!=wh.get_ID()) {
|
|
||||||
M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Update Storage
|
|
||||||
if (!MStorageOnHand.add(getCtx(), line.getM_Warehouse_ID(), M_Locator_ID,
|
|
||||||
line.getM_Product_ID(),
|
line.getM_Product_ID(),
|
||||||
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
|
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
|
||||||
Env.ZERO, get_TrxName()))
|
difference, isSOTrx, get_TrxName()))
|
||||||
return false;
|
return false;
|
||||||
} // stockec
|
} // stocked
|
||||||
// update line
|
// update line
|
||||||
line.setQtyReserved(line.getQtyReserved().add(difference));
|
line.setQtyReserved(line.getQtyReserved().add(difference));
|
||||||
if (!line.save(get_TrxName()))
|
if (!line.save(get_TrxName()))
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.compiere.model;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Timestamp;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
@ -875,7 +876,7 @@ public class MOrderLine extends X_C_OrderLine
|
||||||
{
|
{
|
||||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||||
getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(),
|
getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(),
|
||||||
M_AttributeSet_ID, false, null, true, get_TrxName());
|
null, true, false, 0, get_TrxName());
|
||||||
BigDecimal qty = Env.ZERO;
|
BigDecimal qty = Env.ZERO;
|
||||||
for (int i = 0; i < storages.length; i++)
|
for (int i = 0; i < storages.length; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,7 @@ import org.compiere.util.CCache;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
import org.compiere.util.Msg;
|
import org.compiere.util.Msg;
|
||||||
|
import org.compiere.util.Util;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Product Model
|
* Product Model
|
||||||
|
@ -571,33 +572,8 @@ public class MProduct extends X_M_Product
|
||||||
|| (is_ValueChanged("ProductType") // from Item
|
|| (is_ValueChanged("ProductType") // from Item
|
||||||
&& PRODUCTTYPE_Item.equals(get_ValueOld("ProductType")))))
|
&& PRODUCTTYPE_Item.equals(get_ValueOld("ProductType")))))
|
||||||
{
|
{
|
||||||
// large modified related to storages by zuhri
|
String errMsg = verifyStorage();
|
||||||
MStorageOnHand[] onHandStorages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
if (! Util.isEmpty(errMsg))
|
||||||
MStorageReservation[] reservationStorages = MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
|
||||||
BigDecimal OnHand = Env.ZERO;
|
|
||||||
BigDecimal Ordered = Env.ZERO;
|
|
||||||
BigDecimal Reserved = Env.ZERO;
|
|
||||||
for (int i = 0; i < onHandStorages.length; i++)
|
|
||||||
{
|
|
||||||
OnHand = OnHand.add(onHandStorages[i].getQtyOnHand());
|
|
||||||
|
|
||||||
}
|
|
||||||
for (int i = 0; i < reservationStorages.length; i++)
|
|
||||||
{
|
|
||||||
if(reservationStorages[i].isSOTrx())
|
|
||||||
Reserved = Reserved.add(reservationStorages[i].getQty());
|
|
||||||
else
|
|
||||||
Ordered = Ordered.add(reservationStorages[i].getQty());
|
|
||||||
}
|
|
||||||
// end large modified related to storages by zuhri
|
|
||||||
String errMsg = "";
|
|
||||||
if (OnHand.signum() != 0)
|
|
||||||
errMsg = "@QtyOnHand@ = " + OnHand;
|
|
||||||
if (Ordered.signum() != 0)
|
|
||||||
errMsg += " - @QtyOrdered@ = " + Ordered;
|
|
||||||
if (Reserved.signum() != 0)
|
|
||||||
errMsg += " - @QtyReserved@" + Reserved;
|
|
||||||
if (errMsg.length() > 0)
|
|
||||||
{
|
{
|
||||||
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
||||||
return false;
|
return false;
|
||||||
|
@ -638,6 +614,32 @@ public class MProduct extends X_M_Product
|
||||||
return true;
|
return true;
|
||||||
} // beforeSave
|
} // beforeSave
|
||||||
|
|
||||||
|
private String verifyStorage() {
|
||||||
|
BigDecimal qtyOnHand = Env.ZERO;
|
||||||
|
BigDecimal qtyOrdered = Env.ZERO;
|
||||||
|
BigDecimal qtyReserved = Env.ZERO;
|
||||||
|
for (MStorageOnHand ohs: MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName()))
|
||||||
|
{
|
||||||
|
qtyOnHand = qtyOnHand.add(ohs.getQtyOnHand());
|
||||||
|
}
|
||||||
|
for (MStorageReservation rs : MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName()))
|
||||||
|
{
|
||||||
|
if (rs.isSOTrx())
|
||||||
|
qtyReserved = qtyReserved.add(rs.getQty());
|
||||||
|
else
|
||||||
|
qtyOrdered = qtyOrdered.add(rs.getQty());
|
||||||
|
}
|
||||||
|
|
||||||
|
StringBuilder errMsg = new StringBuilder();
|
||||||
|
if (qtyOnHand.signum() != 0)
|
||||||
|
errMsg.append("@QtyOnHand@ = ").append(qtyOnHand);
|
||||||
|
if (qtyOrdered.signum() != 0)
|
||||||
|
errMsg.append(" - @QtyOrdered@ = ").append(qtyOrdered);
|
||||||
|
if (qtyReserved.signum() != 0)
|
||||||
|
errMsg.append(" - @QtyReserved@").append(qtyReserved);
|
||||||
|
return errMsg.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* HasInventoryOrCost
|
* HasInventoryOrCost
|
||||||
* @return true if it has Inventory or Cost
|
* @return true if it has Inventory or Cost
|
||||||
|
@ -719,31 +721,8 @@ public class MProduct extends X_M_Product
|
||||||
// Check Storage
|
// Check Storage
|
||||||
if (isStocked() || PRODUCTTYPE_Item.equals(getProductType()))
|
if (isStocked() || PRODUCTTYPE_Item.equals(getProductType()))
|
||||||
{
|
{
|
||||||
MStorageOnHand[] storages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
String errMsg = verifyStorage();
|
||||||
MStorageReservation[] reserves = MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
if (! Util.isEmpty(errMsg))
|
||||||
|
|
||||||
BigDecimal OnHand = Env.ZERO;
|
|
||||||
BigDecimal Ordered = Env.ZERO;
|
|
||||||
BigDecimal Reserved = Env.ZERO;
|
|
||||||
for (int i = 0; i < storages.length; i++)
|
|
||||||
{
|
|
||||||
OnHand = OnHand.add(storages[i].getQtyOnHand());
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < reserves.length; i++)
|
|
||||||
{
|
|
||||||
Ordered = OnHand.add(reserves[i].getQtyOrdered());
|
|
||||||
Reserved = OnHand.add(reserves[i].getQtyReserved());
|
|
||||||
}
|
|
||||||
|
|
||||||
String errMsg = "";
|
|
||||||
if (OnHand.signum() != 0)
|
|
||||||
errMsg = "@QtyOnHand@ = " + OnHand;
|
|
||||||
if (Ordered.signum() != 0)
|
|
||||||
errMsg += " - @QtyOrdered@ = " + Ordered;
|
|
||||||
if (Reserved.signum() != 0)
|
|
||||||
errMsg += " - @QtyReserved@" + Reserved;
|
|
||||||
if (errMsg.length() > 0)
|
|
||||||
{
|
{
|
||||||
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -22,11 +22,10 @@ import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.compiere.util.CLogMgt;
|
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
@ -36,14 +35,14 @@ import org.compiere.util.Msg;
|
||||||
* Inventory Storage Model
|
* Inventory Storage Model
|
||||||
*
|
*
|
||||||
* @author Jorg Janke
|
* @author Jorg Janke
|
||||||
* @version $Id: MStorage.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
|
* @version $Id: MStorageOnHand.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
|
||||||
*/
|
*/
|
||||||
public class MStorageOnHand extends X_M_StorageOnHand
|
public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 3911132565445025309L;
|
private static final long serialVersionUID = 3649163126231150631L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Storage Info
|
* Get Storage Info
|
||||||
|
@ -132,12 +131,10 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
public static MStorageOnHand[] getAll (Properties ctx,
|
public static MStorageOnHand[] getAll (Properties ctx,
|
||||||
int M_Product_ID, int M_Locator_ID, String trxName)
|
int M_Product_ID, int M_Locator_ID, String trxName)
|
||||||
{
|
{
|
||||||
String sqlWhere = "M_Product_ID=? AND M_Locator_ID=?"
|
String sqlWhere = "M_Product_ID=? AND M_Locator_ID=? AND QtyOnHand <> 0";
|
||||||
+ " AND QtyOnHand <> 0 "
|
|
||||||
+ "ORDER BY M_AttributeSetInstance_ID";
|
|
||||||
|
|
||||||
List<MStorageOnHand> list = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName)
|
List<MStorageOnHand> list = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName)
|
||||||
.setParameters(M_Product_ID, M_Locator_ID)
|
.setParameters(M_Product_ID, M_Locator_ID)
|
||||||
|
.setOrderBy(MStorageOnHand.COLUMNNAME_M_AttributeSetInstance_ID)
|
||||||
.list();
|
.list();
|
||||||
|
|
||||||
MStorageOnHand[] retValue = new MStorageOnHand[list.size()];
|
MStorageOnHand[] retValue = new MStorageOnHand[list.size()];
|
||||||
|
@ -173,8 +170,8 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
* @param M_Warehouse_ID
|
* @param M_Warehouse_ID
|
||||||
* @param M_Product_ID product
|
* @param M_Product_ID product
|
||||||
* @param M_AttributeSetInstance_ID instance
|
* @param M_AttributeSetInstance_ID instance
|
||||||
* @param M_AttributeSet_ID attribute set
|
* @param M_AttributeSet_ID attribute set (NOT USED)
|
||||||
* @param allAttributeInstances if true, all attribute set instances
|
* @param allAttributeInstances if true, all attribute set instances (NOT USED)
|
||||||
* @param minGuaranteeDate optional minimum guarantee date if all attribute instances
|
* @param minGuaranteeDate optional minimum guarantee date if all attribute instances
|
||||||
* @param FiFo first in-first-out
|
* @param FiFo first in-first-out
|
||||||
* @param trxName transaction
|
* @param trxName transaction
|
||||||
|
@ -219,11 +216,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
// Specific Attribute Set Instance
|
// Specific Attribute Set Instance
|
||||||
String sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
String sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
||||||
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
||||||
//@win change
|
|
||||||
//+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
|
|
||||||
+ "s.QtyOnHand,s.DateLastInventory "
|
+ "s.QtyOnHand,s.DateLastInventory "
|
||||||
//end @win change
|
|
||||||
|
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_StorageOnHand s"
|
||||||
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) ";
|
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) ";
|
||||||
if (M_Locator_ID > 0)
|
if (M_Locator_ID > 0)
|
||||||
|
@ -248,11 +241,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
{
|
{
|
||||||
sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
sql = "SELECT s.M_Product_ID,s.M_Locator_ID,s.M_AttributeSetInstance_ID,"
|
||||||
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
+ "s.AD_Client_ID,s.AD_Org_ID,s.IsActive,s.Created,s.CreatedBy,s.Updated,s.UpdatedBy,"
|
||||||
//@win change
|
+ "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU "
|
||||||
//+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
|
|
||||||
+ "s.QtyOnHand,s.DateLastInventory "
|
|
||||||
//end @win change
|
|
||||||
|
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_StorageOnHand s"
|
||||||
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID)"
|
||||||
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) ";
|
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) ";
|
||||||
|
@ -349,7 +338,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
throw new IllegalArgumentException("Not found M_Locator_ID=" + M_Locator_ID);
|
throw new IllegalArgumentException("Not found M_Locator_ID=" + M_Locator_ID);
|
||||||
//
|
//
|
||||||
retValue = new MStorageOnHand (locator, M_Product_ID, M_AttributeSetInstance_ID);
|
retValue = new MStorageOnHand (locator, M_Product_ID, M_AttributeSetInstance_ID);
|
||||||
retValue.save(trxName);
|
retValue.saveEx(trxName);
|
||||||
s_log.fine("New " + retValue);
|
s_log.fine("New " + retValue);
|
||||||
return retValue;
|
return retValue;
|
||||||
} // getCreate
|
} // getCreate
|
||||||
|
@ -442,7 +431,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
diffText.append(") -> ").append(storage.toString());
|
diffText.append(") -> ").append(storage.toString());
|
||||||
s_log.fine(diffText.toString());
|
s_log.fine(diffText.toString());
|
||||||
if (storage0 != null)
|
if (storage0 != null)
|
||||||
storage0.save(trxName); // No AttributeSetInstance (reserved/ordered)
|
storage0.saveEx(trxName); // No AttributeSetInstance (reserved/ordered)
|
||||||
return storage.save (trxName);
|
return storage.save (trxName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,7 +514,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
//
|
//
|
||||||
setQtyOnHand (Env.ZERO);
|
setQtyOnHand (Env.ZERO);
|
||||||
|
|
||||||
} // MStorage
|
} // MStorageOnHand
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load Constructor
|
* Load Constructor
|
||||||
|
@ -536,7 +525,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
public MStorageOnHand (Properties ctx, ResultSet rs, String trxName)
|
public MStorageOnHand (Properties ctx, ResultSet rs, String trxName)
|
||||||
{
|
{
|
||||||
super(ctx, rs, trxName);
|
super(ctx, rs, trxName);
|
||||||
} // MStorage
|
} // MStorageOnHand
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Full NEW Constructor
|
* Full NEW Constructor
|
||||||
|
@ -551,7 +540,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
setM_Locator_ID (locator.getM_Locator_ID());
|
setM_Locator_ID (locator.getM_Locator_ID());
|
||||||
setM_Product_ID (M_Product_ID);
|
setM_Product_ID (M_Product_ID);
|
||||||
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
|
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
|
||||||
} // MStorage
|
} // MStorageOnHand
|
||||||
|
|
||||||
/** Log */
|
/** Log */
|
||||||
private static CLogger s_log = CLogger.getCLogger (MStorageOnHand.class);
|
private static CLogger s_log = CLogger.getCLogger (MStorageOnHand.class);
|
||||||
|
@ -640,18 +629,18 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static BigDecimal getQtyOnHand(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) {
|
public static BigDecimal getQtyOnHand(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName) {
|
||||||
ArrayList<Object> params = new ArrayList<Object>();
|
|
||||||
StringBuffer sql = new StringBuffer();
|
StringBuffer sql = new StringBuffer();
|
||||||
sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh")
|
sql.append(" SELECT SUM(QtyOnHand) FROM M_StorageOnHand oh JOIN M_Locator loc ON (oh.M_Locator_ID=loc.M_Locator_ID)")
|
||||||
.append(" WHERE oh.M_Product_ID=?")
|
.append(" WHERE oh.M_Product_ID=?")
|
||||||
.append(" AND EXISTS(SELECT 1 FROM M_Locator loc WHERE oh.M_Locator_ID=loc.M_Locator_ID AND loc.M_Warehouse_ID=?)");
|
.append(" AND loc.M_Warehouse_ID=?");
|
||||||
|
|
||||||
|
ArrayList<Object> params = new ArrayList<Object>();
|
||||||
params.add(M_Product_ID);
|
params.add(M_Product_ID);
|
||||||
params.add(M_Warehouse_ID);
|
params.add(M_Warehouse_ID);
|
||||||
|
|
||||||
// With ASI
|
// With ASI
|
||||||
if (M_AttributeSetInstance_ID != 0) {
|
if (M_AttributeSetInstance_ID != 0) {
|
||||||
sql.append(" AND M_AttributeSetInstance_ID=?");
|
sql.append(" AND oh.M_AttributeSetInstance_ID=?");
|
||||||
params.add(M_AttributeSetInstance_ID);
|
params.add(M_AttributeSetInstance_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -668,7 +657,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
*/
|
*/
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuffer sb = new StringBuffer("MStorage[")
|
StringBuffer sb = new StringBuffer("MStorageOnHand[")
|
||||||
.append("M_Locator_ID=").append(getM_Locator_ID())
|
.append("M_Locator_ID=").append(getM_Locator_ID())
|
||||||
.append(",M_Product_ID=").append(getM_Product_ID())
|
.append(",M_Product_ID=").append(getM_Product_ID())
|
||||||
.append(",M_AttributeSetInstance_ID=").append(getM_AttributeSetInstance_ID())
|
.append(",M_AttributeSetInstance_ID=").append(getM_AttributeSetInstance_ID())
|
||||||
|
@ -681,4 +670,4 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
} // MStorage
|
} // MStorageOnHand
|
||||||
|
|
|
@ -1,36 +1,118 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Product: iDempiere ERP & CRM Smart Business Solution *
|
||||||
|
* Copyright (C) 1999-2012 iDempiere 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. *
|
||||||
|
*****************************************************************************/
|
||||||
package org.compiere.model;
|
package org.compiere.model;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import org.compiere.util.CLogMgt;
|
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
|
||||||
public class MStorageReservation extends X_M_StorageReservation {
|
public class MStorageReservation extends X_M_StorageReservation {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 8114446879871270122L;
|
private static final long serialVersionUID = -8646802850122507899L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Storage Info
|
||||||
|
* @param ctx context
|
||||||
|
* @param M_Warehouse_ID warehouse
|
||||||
|
* @param M_Product_ID product
|
||||||
|
* @param M_AttributeSetInstance_ID instance
|
||||||
|
* @param isSOTrx
|
||||||
|
* @param trxName transaction
|
||||||
|
* @return existing or null
|
||||||
|
*/
|
||||||
|
public static MStorageReservation get (Properties ctx, int M_Warehouse_ID,
|
||||||
|
int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName)
|
||||||
|
{
|
||||||
|
MStorageReservation retValue = null;
|
||||||
|
String sql = "SELECT * FROM M_StorageReservation "
|
||||||
|
+ "WHERE M_Warehouse_ID=? AND M_Product_ID=? AND IsSOTrx=? AND ";
|
||||||
|
if (M_AttributeSetInstance_ID == 0)
|
||||||
|
sql += "(M_AttributeSetInstance_ID=? OR M_AttributeSetInstance_ID IS NULL)";
|
||||||
|
else
|
||||||
|
sql += "M_AttributeSetInstance_ID=?";
|
||||||
|
PreparedStatement pstmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pstmt = DB.prepareStatement (sql, trxName);
|
||||||
|
pstmt.setInt (1, M_Warehouse_ID);
|
||||||
|
pstmt.setInt (2, M_Product_ID);
|
||||||
|
pstmt.setString (3, isSOTrx ? "Y" : "N");
|
||||||
|
pstmt.setInt (4, M_AttributeSetInstance_ID);
|
||||||
|
rs = pstmt.executeQuery ();
|
||||||
|
if (rs.next ())
|
||||||
|
retValue = new MStorageReservation (ctx, rs, trxName);
|
||||||
|
}
|
||||||
|
catch (SQLException ex)
|
||||||
|
{
|
||||||
|
s_log.log(Level.SEVERE, sql, ex);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DB.close(rs, pstmt);
|
||||||
|
rs = null; pstmt = null;
|
||||||
|
}
|
||||||
|
if (retValue == null)
|
||||||
|
s_log.fine("Not Found - M_Warehouse_ID=" + M_Warehouse_ID
|
||||||
|
+ ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID + ", IsSOTrx=" + isSOTrx);
|
||||||
|
else
|
||||||
|
s_log.fine("M_Warehouse_ID=" + M_Warehouse_ID
|
||||||
|
+ ", M_Product_ID=" + M_Product_ID + ", M_AttributeSetInstance_ID=" + M_AttributeSetInstance_ID + ", IsSOTrx=" + isSOTrx);
|
||||||
|
return retValue;
|
||||||
|
} // get
|
||||||
|
|
||||||
private static CLogger s_log = CLogger.getCLogger(MStorageReservation.class);
|
private static CLogger s_log = CLogger.getCLogger(MStorageReservation.class);
|
||||||
|
|
||||||
public MStorageReservation(Properties ctx, int M_StorageReservation_ID,
|
public MStorageReservation(Properties ctx, int M_StorageReservation_ID,
|
||||||
String trxName) {
|
String trxName) {
|
||||||
super(ctx, M_StorageReservation_ID, trxName);
|
super(ctx, M_StorageReservation_ID, trxName);
|
||||||
// TODO Auto-generated constructor stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public MStorageReservation(Properties ctx, ResultSet rs,
|
public MStorageReservation(Properties ctx, ResultSet rs,
|
||||||
String trxName) {
|
String trxName) {
|
||||||
super(ctx, rs, trxName);
|
super(ctx, rs, trxName);
|
||||||
// TODO Auto-generated constructor stub
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Full NEW Constructor
|
||||||
|
* @param warehouse (parent) warehouse
|
||||||
|
* @param M_Product_ID product
|
||||||
|
* @param M_AttributeSetInstance_ID attribute
|
||||||
|
* @param isSOTrx
|
||||||
|
*/
|
||||||
|
private MStorageReservation (MWarehouse warehouse, int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx)
|
||||||
|
{
|
||||||
|
this (warehouse.getCtx(), 0, warehouse.get_TrxName());
|
||||||
|
setClientOrg(warehouse);
|
||||||
|
setM_Warehouse_ID(warehouse.getM_Warehouse_ID());
|
||||||
|
setM_Product_ID (M_Product_ID);
|
||||||
|
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
|
||||||
|
setIsSOTrx(isSOTrx);
|
||||||
|
setQty(Env.ZERO);
|
||||||
|
} // MStorageReservation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Storage Info for Product on specified Warehouse
|
* Get Storage Info for Product on specified Warehouse
|
||||||
* @param ctx
|
* @param ctx
|
||||||
|
@ -74,25 +156,25 @@ public class MStorageReservation extends X_M_StorageReservation {
|
||||||
|
|
||||||
} // getOfProduct
|
} // getOfProduct
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Quantity Reserved of Warehouse
|
* Get Quantity Reserved of Warehouse
|
||||||
* @param M_Product_ID
|
* @param M_Product_ID
|
||||||
* @param M_Warehouse_ID
|
* @param M_Warehouse_ID
|
||||||
* @param M_AttributeSetInstance_ID
|
* @param M_AttributeSetInstance_ID
|
||||||
|
* @param isSOTrx - true to get reserved, false to get ordered
|
||||||
* @param trxName
|
* @param trxName
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
public static BigDecimal getQtyReserved(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, String trxName){
|
private static BigDecimal getQty(int M_Product_ID, int M_Warehouse_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName) {
|
||||||
ArrayList<Object> params = new ArrayList<Object>();
|
ArrayList<Object> params = new ArrayList<Object>();
|
||||||
StringBuffer sql = new StringBuffer();
|
StringBuffer sql = new StringBuffer();
|
||||||
sql.append(" SELECT SUM(Qty) FROM M_StorageReservation oh")
|
sql.append(" SELECT SUM(Qty) FROM M_StorageReservation sr")
|
||||||
.append(" WHERE oh.M_Product_ID=? AND oh.M_Warehouse_ID=?")
|
.append(" WHERE sr.M_Product_ID=? AND sr.M_Warehouse_ID=?")
|
||||||
.append(" AND oh.IsSOTrx='Y'");
|
.append(" AND sr.IsSOTrx=?");
|
||||||
|
|
||||||
params.add(M_Product_ID);
|
params.add(M_Product_ID);
|
||||||
params.add(M_Warehouse_ID);
|
params.add(M_Warehouse_ID);
|
||||||
|
params.add(isSOTrx ? "Y" : "N");
|
||||||
|
|
||||||
// With ASI
|
// With ASI
|
||||||
if (M_AttributeSetInstance_ID != 0) {
|
if (M_AttributeSetInstance_ID != 0) {
|
||||||
|
@ -107,13 +189,6 @@ public class MStorageReservation extends X_M_StorageReservation {
|
||||||
return qty;
|
return qty;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static BigDecimal getQtyOrdered (int M_Warehouse_ID,
|
|
||||||
int M_Product_ID, int M_AttributeSetInstance_ID, String trxName)
|
|
||||||
{
|
|
||||||
BigDecimal retValue = null;
|
|
||||||
return retValue;
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Get Available Qty.
|
* Get Available Qty.
|
||||||
* The call is accurate only if there is a storage record
|
* The call is accurate only if there is a storage record
|
||||||
|
@ -128,19 +203,116 @@ public class MStorageReservation extends X_M_StorageReservation {
|
||||||
int M_Product_ID, int M_AttributeSetInstance_ID, String trxName)
|
int M_Product_ID, int M_AttributeSetInstance_ID, String trxName)
|
||||||
{
|
{
|
||||||
BigDecimal qtyOnHand = MStorageOnHand.getQtyOnHand(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, trxName);
|
BigDecimal qtyOnHand = MStorageOnHand.getQtyOnHand(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, trxName);
|
||||||
BigDecimal qtyReserved = getQtyReserved(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, trxName);
|
BigDecimal qtyReserved = MStorageReservation.getQty(M_Product_ID, M_Warehouse_ID, M_AttributeSetInstance_ID, true, trxName);
|
||||||
BigDecimal retValue = qtyOnHand.subtract(qtyReserved);
|
BigDecimal retValue = qtyOnHand.subtract(qtyReserved);
|
||||||
return retValue;
|
return retValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getQtyOrdered() {
|
/**
|
||||||
// TODO Auto-generated method stub
|
* Update Storage Info add.
|
||||||
return null;
|
* Called from MProjectIssue
|
||||||
|
* @param ctx context
|
||||||
|
* @param M_Warehouse_ID warehouse
|
||||||
|
* @param M_Product_ID product
|
||||||
|
* @param M_AttributeSetInstance_ID AS Instance
|
||||||
|
* @param reservationAttributeSetInstance_ID reservation AS Instance
|
||||||
|
* @param diffQty add
|
||||||
|
* @param isSOTrx
|
||||||
|
* @param trxName transaction
|
||||||
|
* @return true if updated
|
||||||
|
*/
|
||||||
|
public static boolean add (Properties ctx, int M_Warehouse_ID,
|
||||||
|
int M_Product_ID, int M_AttributeSetInstance_ID, int reservationAttributeSetInstance_ID,
|
||||||
|
BigDecimal diffQty, boolean isSOTrx, String trxName)
|
||||||
|
{
|
||||||
|
/* Do NOT use FIFO ASI for reservation */
|
||||||
|
MProduct prd = new MProduct(ctx, M_Product_ID, trxName);
|
||||||
|
if (prd.getM_AttributeSet_ID() == 0 || ! prd.getM_AttributeSet().isInstanceAttribute()) {
|
||||||
|
// Product doesn't manage attribute set, always reserved with 0
|
||||||
|
reservationAttributeSetInstance_ID = 0;
|
||||||
|
M_AttributeSetInstance_ID = 0;
|
||||||
|
}
|
||||||
|
//
|
||||||
|
|
||||||
|
MStorageReservation storage = null;
|
||||||
|
StringBuffer diffText = new StringBuffer("(");
|
||||||
|
|
||||||
|
// Get Storage
|
||||||
|
if (storage == null)
|
||||||
|
storage = getCreate (ctx, M_Warehouse_ID,
|
||||||
|
M_Product_ID, M_AttributeSetInstance_ID, isSOTrx, trxName);
|
||||||
|
// Verify
|
||||||
|
if (storage.getM_Warehouse_ID() != M_Warehouse_ID
|
||||||
|
&& storage.getM_Product_ID() != M_Product_ID
|
||||||
|
&& storage.getM_AttributeSetInstance_ID() != M_AttributeSetInstance_ID)
|
||||||
|
{
|
||||||
|
s_log.severe ("No Storage found - M_Warehouse_ID=" + M_Warehouse_ID
|
||||||
|
+ ",M_Product_ID=" + M_Product_ID + ",ASI=" + M_AttributeSetInstance_ID);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BigDecimal getQtyReserved() {
|
MStorageReservation storage0 = null;
|
||||||
// TODO Auto-generated method stub
|
if (M_AttributeSetInstance_ID != reservationAttributeSetInstance_ID)
|
||||||
return null;
|
{
|
||||||
|
storage0 = get(ctx, M_Warehouse_ID,
|
||||||
|
M_Product_ID, reservationAttributeSetInstance_ID, isSOTrx, trxName);
|
||||||
|
if (storage0 == null) // create if not existing - should not happen
|
||||||
|
{
|
||||||
|
storage0 = getCreate (ctx, M_Warehouse_ID,
|
||||||
|
M_Product_ID, reservationAttributeSetInstance_ID, isSOTrx, trxName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
boolean changed = false;
|
||||||
|
if (diffQty != null && diffQty.signum() != 0)
|
||||||
|
{
|
||||||
|
if (storage0 == null)
|
||||||
|
storage.setQty (storage.getQty().add(diffQty));
|
||||||
|
else
|
||||||
|
storage0.setQty (storage0.getQty().add (diffQty));
|
||||||
|
diffText.append(" Qty=").append(diffQty);
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
if (changed)
|
||||||
|
{
|
||||||
|
diffText.append(") -> ").append(storage.toString());
|
||||||
|
s_log.fine(diffText.toString());
|
||||||
|
if (storage0 != null)
|
||||||
|
storage0.saveEx(trxName); // No AttributeSetInstance
|
||||||
|
return storage.save (trxName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} // add
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or Get Storage Info
|
||||||
|
* @param ctx context
|
||||||
|
* @param M_Locator_ID locator
|
||||||
|
* @param M_Product_ID product
|
||||||
|
* @param M_AttributeSetInstance_ID instance
|
||||||
|
* @param trxName transaction
|
||||||
|
* @return existing/new or null
|
||||||
|
*/
|
||||||
|
public static MStorageReservation getCreate (Properties ctx, int M_Warehouse_ID,
|
||||||
|
int M_Product_ID, int M_AttributeSetInstance_ID, boolean isSOTrx, String trxName)
|
||||||
|
{
|
||||||
|
if (M_Warehouse_ID == 0)
|
||||||
|
throw new IllegalArgumentException("M_Warehouse_ID=0");
|
||||||
|
if (M_Product_ID == 0)
|
||||||
|
throw new IllegalArgumentException("M_Product_ID=0");
|
||||||
|
MStorageReservation retValue = get(ctx, M_Warehouse_ID, M_Product_ID, M_AttributeSetInstance_ID, isSOTrx, trxName);
|
||||||
|
if (retValue != null)
|
||||||
|
return retValue;
|
||||||
|
|
||||||
|
// Insert row based on warehouse
|
||||||
|
MWarehouse warehouse = new MWarehouse (ctx, M_Warehouse_ID, trxName);
|
||||||
|
if (warehouse.get_ID() != M_Warehouse_ID)
|
||||||
|
throw new IllegalArgumentException("Not found M_Warehouse_ID=" + M_Warehouse_ID);
|
||||||
|
//
|
||||||
|
retValue = new MStorageReservation (warehouse, M_Product_ID, M_AttributeSetInstance_ID, isSOTrx);
|
||||||
|
retValue.saveEx(trxName);
|
||||||
|
s_log.fine("New " + retValue);
|
||||||
|
return retValue;
|
||||||
|
} // getCreate
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import java.util.Properties;
|
||||||
|
|
||||||
import org.compiere.model.MAttributeSet;
|
import org.compiere.model.MAttributeSet;
|
||||||
import org.compiere.model.MCharge;
|
import org.compiere.model.MCharge;
|
||||||
|
import org.compiere.model.MClient;
|
||||||
import org.compiere.model.MLocator;
|
import org.compiere.model.MLocator;
|
||||||
import org.compiere.model.MProduct;
|
import org.compiere.model.MProduct;
|
||||||
import org.compiere.model.MStorageOnHand;
|
import org.compiere.model.MStorageOnHand;
|
||||||
|
@ -579,7 +580,7 @@ public class MDDOrderLine extends X_DD_OrderLine
|
||||||
MLocator locator_from = MLocator.get(getCtx(), getM_Locator_ID());
|
MLocator locator_from = MLocator.get(getCtx(), getM_Locator_ID());
|
||||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||||
locator_from.getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(),
|
locator_from.getM_Warehouse_ID(), getM_Product_ID(), getM_AttributeSetInstance_ID(),
|
||||||
M_AttributeSet_ID, false, null, true, get_TrxName());
|
null, true, false, 0, get_TrxName());
|
||||||
BigDecimal qty = Env.ZERO;
|
BigDecimal qty = Env.ZERO;
|
||||||
for (int i = 0; i < storages.length; i++)
|
for (int i = 0; i < storages.length; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -512,7 +512,7 @@ public class InfoPAttribute extends CDialog
|
||||||
// finish Instance Attributes
|
// finish Instance Attributes
|
||||||
if (sb.length() > 0)
|
if (sb.length() > 0)
|
||||||
{
|
{
|
||||||
sb.insert(0, " AND EXISTS (SELECT * FROM M_StorageOnHand s"
|
sb.insert(0, " AND EXISTS (SELECT * FROM M_Storage s"
|
||||||
+ " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "
|
+ " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "
|
||||||
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
|
|
|
@ -1240,23 +1240,21 @@ public class InfoProduct extends Info implements ActionListener, ChangeListener
|
||||||
|
|
||||||
// Fill Storage Data
|
// Fill Storage Data
|
||||||
boolean showDetail = CLogMgt.isLevelFine();
|
boolean showDetail = CLogMgt.isLevelFine();
|
||||||
String sql = "SELECT s.QtyOnHand, r.Qty as QtyReserved, o.Qty as QtyOrdered,"
|
String sql = "SELECT s.QtyOnHand, s.QtyReserved, s.QtyOrdered,"
|
||||||
+ " productAttribute(s.M_AttributeSetInstance_ID), s.M_AttributeSetInstance_ID,";
|
+ " productAttribute(s.M_AttributeSetInstance_ID), s.M_AttributeSetInstance_ID,";
|
||||||
if (!showDetail)
|
if (!showDetail)
|
||||||
sql = "SELECT SUM(s.QtyOnHand), SUM(r.Qty), SUM(o.Qty),"
|
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
||||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||||
sql += " w.Name, l.Value "
|
sql += " w.Name, l.Value "
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
||||||
+ " LEFT JOIN M_StorageReservation r ON (s.M_Product_ID=r.M_Product_ID AND w.M_Warehouse_ID=r.M_Warehouse_ID AND r.IsSOTrx='Y') "
|
+ "WHERE M_Product_ID=?";
|
||||||
+ " LEFT JOIN M_StorageReservation o ON (s.M_Product_ID=o.M_Product_ID AND w.M_Warehouse_ID=o.M_Warehouse_ID AND o.IsSOTrx='N') "
|
|
||||||
+ "WHERE s.M_Product_ID=?";
|
|
||||||
if (m_M_Warehouse_ID != 0)
|
if (m_M_Warehouse_ID != 0)
|
||||||
sql += " AND l.M_Warehouse_ID=?";
|
sql += " AND l.M_Warehouse_ID=?";
|
||||||
if (m_M_AttributeSetInstance_ID > 0)
|
if (m_M_AttributeSetInstance_ID > 0)
|
||||||
sql += " AND s.M_AttributeSetInstance_ID=?";
|
sql += " AND s.M_AttributeSetInstance_ID=?";
|
||||||
sql += " AND (s.QtyOnHand<>0 OR r.Qty<>0 OR o.Qty<>0)";
|
sql += " AND (s.QtyOnHand<>0 OR s.QtyReserved<>0 OR s.QtyOrdered<>0)";
|
||||||
if (!showDetail)
|
if (!showDetail)
|
||||||
sql += " GROUP BY productAttribute(s.M_AttributeSetInstance_ID), w.Name, l.Value";
|
sql += " GROUP BY productAttribute(s.M_AttributeSetInstance_ID), w.Name, l.Value";
|
||||||
sql += " ORDER BY l.Value";
|
sql += " ORDER BY l.Value";
|
||||||
|
|
|
@ -566,7 +566,7 @@ public class InvoiceHistory extends CDialog
|
||||||
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
||||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||||
sql += " w.Name, l.Value "
|
sql += " w.Name, l.Value "
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
||||||
+ "WHERE M_Product_ID=?";
|
+ "WHERE M_Product_ID=?";
|
||||||
|
|
|
@ -178,7 +178,7 @@ public class PAttributeInstance extends CDialog
|
||||||
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
||||||
};
|
};
|
||||||
/** From Clause */
|
/** From Clause */
|
||||||
private static String s_sqlFrom = "M_StorageOnHand s"
|
private static String s_sqlFrom = "M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
||||||
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
||||||
|
|
|
@ -456,7 +456,7 @@ public class VLocator extends JComponent
|
||||||
sql.append(" AND (IsDefault='Y' ") // Default Locator
|
sql.append(" AND (IsDefault='Y' ") // Default Locator
|
||||||
.append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator
|
.append("OR EXISTS (SELECT * FROM M_Product p ") // Product Locator
|
||||||
.append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)")
|
.append("WHERE p.M_Locator_ID=M_Locator.M_Locator_ID AND p.M_Product_ID=?)")
|
||||||
.append("OR EXISTS (SELECT * FROM M_StorageOnHand s ") // Storage Locator
|
.append("OR EXISTS (SELECT * FROM M_Storage s ") // Storage Locator
|
||||||
.append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))");
|
.append("WHERE s.M_Locator_ID=M_Locator.M_Locator_ID AND s.M_Product_ID=?))");
|
||||||
String finalSql = MRole.getDefault(Env.getCtx(), false).addAccessSQL(
|
String finalSql = MRole.getDefault(Env.getCtx(), false).addAccessSQL(
|
||||||
sql.toString(), "M_Locator", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
|
sql.toString(), "M_Locator", MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
|
||||||
|
|
|
@ -166,7 +166,7 @@ public class InfoPAttributeInstancePanel extends Window implements EventListener
|
||||||
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
||||||
};
|
};
|
||||||
/** From Clause */
|
/** From Clause */
|
||||||
private static String s_sqlFrom = "M_StorageOnHand s"
|
private static String s_sqlFrom = "M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
||||||
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
||||||
|
|
|
@ -614,7 +614,7 @@ public class InfoPAttributePanel extends Window implements EventListener
|
||||||
// finish Instance Attributes
|
// finish Instance Attributes
|
||||||
if (sb.length() > 0)
|
if (sb.length() > 0)
|
||||||
{
|
{
|
||||||
sb.insert(0, " AND EXISTS (SELECT * FROM M_StorageOnHand s"
|
sb.insert(0, " AND EXISTS (SELECT * FROM M_Storage s"
|
||||||
+ " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "
|
+ " INNER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID) "
|
||||||
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
||||||
sb.append(")");
|
sb.append(")");
|
||||||
|
|
|
@ -1453,7 +1453,7 @@ public class InfoProductPanel extends InfoPanel implements EventListener
|
||||||
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
||||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||||
sql += " w.Name, l.Value "
|
sql += " w.Name, l.Value "
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
||||||
+ "WHERE M_Product_ID=?";
|
+ "WHERE M_Product_ID=?";
|
||||||
|
|
|
@ -599,7 +599,7 @@ public class InvoiceHistory extends Window implements EventListener
|
||||||
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
||||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||||
sql += " w.Name, l.Value "
|
sql += " w.Name, l.Value "
|
||||||
+ "FROM M_StorageOnHand s"
|
+ "FROM M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
+ " INNER JOIN M_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_ID) "
|
||||||
+ "WHERE M_Product_ID=?";
|
+ "WHERE M_Product_ID=?";
|
||||||
|
|
|
@ -173,7 +173,7 @@ public class WPAttributeInstance extends Window implements EventListener
|
||||||
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
new ColumnInfo(Msg.translate(Env.getCtx(), "ShelfLifeRemainingPct"), "CASE WHEN p.GuaranteeDays > 0 THEN TRUNC(((daysbetween(asi.GuaranteeDate, SYSDATE))/p.GuaranteeDays)*100) ELSE 0 END", Integer.class),
|
||||||
};
|
};
|
||||||
/** From Clause */
|
/** From Clause */
|
||||||
private static String s_sqlFrom = "M_StorageOnHand s"
|
private static String s_sqlFrom = "M_Storage s"
|
||||||
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
+ " INNER JOIN M_Locator l ON (s.M_Locator_ID=l.M_Locator_ID)"
|
||||||
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
+ " INNER JOIN M_Product p ON (s.M_Product_ID=p.M_Product_ID)"
|
||||||
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
+ " LEFT OUTER JOIN M_AttributeSetInstance asi ON (s.M_AttributeSetInstance_ID=asi.M_AttributeSetInstance_ID)";
|
||||||
|
|
|
@ -32,6 +32,7 @@ import org.compiere.model.MMatchPO;
|
||||||
import org.compiere.model.MOrderLine;
|
import org.compiere.model.MOrderLine;
|
||||||
import org.compiere.model.MRole;
|
import org.compiere.model.MRole;
|
||||||
import org.compiere.model.MStorageOnHand;
|
import org.compiere.model.MStorageOnHand;
|
||||||
|
import org.compiere.model.MStorageReservation;
|
||||||
import org.compiere.process.DocumentEngine;
|
import org.compiere.process.DocumentEngine;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
|
@ -491,11 +492,10 @@ public class Match
|
||||||
success = true;
|
success = true;
|
||||||
// Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt)
|
// Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt)
|
||||||
if (sLine.getProduct() != null && sLine.getProduct().isStocked())
|
if (sLine.getProduct() != null && sLine.getProduct().isStocked())
|
||||||
success = MStorageOnHand.add (Env.getCtx(), sLine.getM_Warehouse_ID(),
|
success = MStorageReservation.add (Env.getCtx(), sLine.getM_Warehouse_ID(),
|
||||||
sLine.getM_Locator_ID(),
|
|
||||||
sLine.getM_Product_ID(),
|
sLine.getM_Product_ID(),
|
||||||
sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(),
|
sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(),
|
||||||
null, trxName);
|
qty.negate(), false, trxName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue