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)
|
||||
MovementQty = (BigDecimal) mTab.getValue("MovementQty");
|
||||
int M_Locator_ID = Env.getContextAsInt(ctx, WindowNo, "M_Locator_ID");
|
||||
|
||||
// If no locator, don't check anything and assume is ok
|
||||
if (M_Locator_ID <= 0)
|
||||
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");
|
||||
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)
|
||||
available = Env.ZERO;
|
||||
if (available.signum() == 0)
|
||||
|
|
|
@ -150,6 +150,16 @@ public class OrgOwnership extends SvrProcess
|
|||
no = DB.executeUpdate(sql.toString(), get_TrxName());
|
||||
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 "";
|
||||
} // warehouseOwnership
|
||||
|
||||
|
|
|
@ -251,10 +251,10 @@ public class ReplenishReport extends SvrProcess
|
|||
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(" 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(" AND l.M_Warehouse_ID=t.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(" AND l.M_Warehouse_ID=t.M_Warehouse_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 t.M_Warehouse_ID=s.M_Warehouse_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 t.M_Warehouse_ID=s.M_Warehouse_ID)");
|
||||
if (p_C_DocType_ID != 0)
|
||||
sql.append(", C_DocType_ID=").append(p_C_DocType_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());
|
||||
String MMPolicy = product.getMMPolicy();
|
||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0,
|
||||
true, null,
|
||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
|
||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null,
|
||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName());
|
||||
//
|
||||
BigDecimal target = replenish.getQtyToOrder();
|
||||
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.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("QtyReserved = (SELECT COALESCE(SUM(QtyReserved),0) FROM M_StorageReservation s, M_Locator l WHERE t.M_Product_ID=s.M_Product_ID");
|
||||
sql.append(" AND l.M_Warehouse_ID=t.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(" AND l.M_Warehouse_ID=t.M_Warehouse_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 t.M_Warehouse_ID=s.M_Warehouse_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 t.M_Warehouse_ID=s.M_Warehouse_ID)");
|
||||
if (p_C_DocType_ID != 0)
|
||||
sql.append(", C_DocType_ID=").append(p_C_DocType_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());
|
||||
String MMPolicy = product.getMMPolicy();
|
||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, 0,
|
||||
true, null,
|
||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), get_TrxName());
|
||||
whSource.getM_Warehouse_ID(), replenish.getM_Product_ID(), 0, null,
|
||||
MClient.MMPOLICY_FiFo.equals(MMPolicy), false, 0, get_TrxName());
|
||||
//
|
||||
BigDecimal target = replenish.getQtyToOrder();
|
||||
for (int j = 0; j < storages.length; j++)
|
||||
|
|
|
@ -69,11 +69,18 @@ public class StorageCleanup extends SvrProcess
|
|||
log.info("");
|
||||
// Clean up empty Storage
|
||||
String sql = "DELETE FROM M_StorageOnHand "
|
||||
+ "WHERE QtyOnHand = 0 AND QtyReserved = 0 AND QtyOrdered = 0"
|
||||
+ "WHERE QtyOnHand = 0"
|
||||
+ " AND Created < SysDate-3";
|
||||
int no = DB.executeUpdate(sql, get_TrxName());
|
||||
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 * "
|
||||
+ "FROM M_StorageOnHand s "
|
||||
|
|
|
@ -1361,22 +1361,60 @@ public class MInOut extends X_M_InOut implements DocAction
|
|||
get_TrxName()))
|
||||
{
|
||||
String lastError = CLogger.retrieveErrorString("");
|
||||
m_processMsg = "Cannot correct Inventory (MA) - " + lastError;
|
||||
m_processMsg = "Cannot correct Inventory OnHand (MA) - " + lastError;
|
||||
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) {
|
||||
//correct qtyOrdered in warehouse of order
|
||||
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
||||
if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||
wh.getDefaultLocator().getM_Locator_ID(),
|
||||
if (reservedDiff.signum() != 0) {
|
||||
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||
sLine.getM_Product_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;
|
||||
}
|
||||
}
|
||||
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
|
||||
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_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,
|
||||
Qty, get_TrxName()))
|
||||
{
|
||||
m_processMsg = "Cannot correct Inventory";
|
||||
m_processMsg = "Cannot correct Inventory OnHand";
|
||||
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) {
|
||||
//correct qtyOrdered in warehouse of order
|
||||
MWarehouse wh = MWarehouse.get(getCtx(), oLine.getM_Warehouse_ID());
|
||||
if (!MStorageOnHand.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||
wh.getDefaultLocator().getM_Locator_ID(),
|
||||
if (QtySO.signum() != 0) {
|
||||
if (!MStorageReservation.add(getCtx(), oLine.getM_Warehouse_ID(),
|
||||
sLine.getM_Product_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;
|
||||
}
|
||||
}
|
||||
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
|
||||
mtrx = new MTransaction (getCtx(), sLine.getAD_Org_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
|
||||
.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("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=?))");
|
||||
sql.append(" ORDER BY ");
|
||||
if (local_only_warehouse_id == 0)
|
||||
|
|
|
@ -1566,38 +1566,13 @@ public class MOrder extends X_C_Order implements DocAction
|
|||
{
|
||||
if (product.isStocked())
|
||||
{
|
||||
BigDecimal ordered = isSOTrx ? Env.ZERO : difference;
|
||||
BigDecimal reserved = isSOTrx ? difference : Env.ZERO;
|
||||
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,
|
||||
// Update Reservation Storage
|
||||
if (!MStorageReservation.add(getCtx(), line.getM_Warehouse_ID(),
|
||||
line.getM_Product_ID(),
|
||||
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
|
||||
Env.ZERO, get_TrxName()))
|
||||
difference, isSOTrx, get_TrxName()))
|
||||
return false;
|
||||
} // stockec
|
||||
} // stocked
|
||||
// update line
|
||||
line.setQtyReserved(line.getQtyReserved().add(difference));
|
||||
if (!line.save(get_TrxName()))
|
||||
|
|
|
@ -19,6 +19,7 @@ package org.compiere.model;
|
|||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
@ -875,7 +876,7 @@ public class MOrderLine extends X_C_OrderLine
|
|||
{
|
||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||
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;
|
||||
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.Env;
|
||||
import org.compiere.util.Msg;
|
||||
import org.compiere.util.Util;
|
||||
|
||||
/**
|
||||
* Product Model
|
||||
|
@ -571,33 +572,8 @@ public class MProduct extends X_M_Product
|
|||
|| (is_ValueChanged("ProductType") // from Item
|
||||
&& PRODUCTTYPE_Item.equals(get_ValueOld("ProductType")))))
|
||||
{
|
||||
// large modified related to storages by zuhri
|
||||
MStorageOnHand[] onHandStorages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
||||
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)
|
||||
String errMsg = verifyStorage();
|
||||
if (! Util.isEmpty(errMsg))
|
||||
{
|
||||
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
||||
return false;
|
||||
|
@ -638,6 +614,32 @@ public class MProduct extends X_M_Product
|
|||
return true;
|
||||
} // 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
|
||||
* @return true if it has Inventory or Cost
|
||||
|
@ -719,31 +721,8 @@ public class MProduct extends X_M_Product
|
|||
// Check Storage
|
||||
if (isStocked() || PRODUCTTYPE_Item.equals(getProductType()))
|
||||
{
|
||||
MStorageOnHand[] storages = MStorageOnHand.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
||||
MStorageReservation[] reserves = MStorageReservation.getOfProduct(getCtx(), get_ID(), get_TrxName());
|
||||
|
||||
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)
|
||||
String errMsg = verifyStorage();
|
||||
if (! Util.isEmpty(errMsg))
|
||||
{
|
||||
log.saveError("Error", Msg.parseTranslation(getCtx(), errMsg));
|
||||
return false;
|
||||
|
|
|
@ -22,11 +22,10 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
import java.util.List;
|
||||
|
||||
import org.compiere.util.CLogMgt;
|
||||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
|
@ -36,14 +35,14 @@ import org.compiere.util.Msg;
|
|||
* Inventory Storage Model
|
||||
*
|
||||
* @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
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 3911132565445025309L;
|
||||
private static final long serialVersionUID = 3649163126231150631L;
|
||||
|
||||
/**
|
||||
* Get Storage Info
|
||||
|
@ -132,12 +131,10 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
public static MStorageOnHand[] getAll (Properties ctx,
|
||||
int M_Product_ID, int M_Locator_ID, String trxName)
|
||||
{
|
||||
String sqlWhere = "M_Product_ID=? AND M_Locator_ID=?"
|
||||
+ " AND QtyOnHand <> 0 "
|
||||
+ "ORDER BY M_AttributeSetInstance_ID";
|
||||
|
||||
String sqlWhere = "M_Product_ID=? AND M_Locator_ID=? AND QtyOnHand <> 0";
|
||||
List<MStorageOnHand> list = new Query(ctx, MStorageOnHand.Table_Name, sqlWhere, trxName)
|
||||
.setParameters(M_Product_ID, M_Locator_ID)
|
||||
.setOrderBy(MStorageOnHand.COLUMNNAME_M_AttributeSetInstance_ID)
|
||||
.list();
|
||||
|
||||
MStorageOnHand[] retValue = new MStorageOnHand[list.size()];
|
||||
|
@ -173,8 +170,8 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
* @param M_Warehouse_ID
|
||||
* @param M_Product_ID product
|
||||
* @param M_AttributeSetInstance_ID instance
|
||||
* @param M_AttributeSet_ID attribute set
|
||||
* @param allAttributeInstances if true, all attribute set instances
|
||||
* @param M_AttributeSet_ID attribute set (NOT USED)
|
||||
* @param allAttributeInstances if true, all attribute set instances (NOT USED)
|
||||
* @param minGuaranteeDate optional minimum guarantee date if all attribute instances
|
||||
* @param FiFo first in-first-out
|
||||
* @param trxName transaction
|
||||
|
@ -219,11 +216,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
// Specific Attribute Set Instance
|
||||
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,"
|
||||
//@win change
|
||||
//+ "s.QtyOnHand,s.QtyReserved,s.QtyOrdered,s.DateLastInventory "
|
||||
+ "s.QtyOnHand,s.DateLastInventory "
|
||||
//end @win change
|
||||
|
||||
+ "FROM M_StorageOnHand s"
|
||||
+ " INNER JOIN M_Locator l ON (l.M_Locator_ID=s.M_Locator_ID) ";
|
||||
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,"
|
||||
+ "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 "
|
||||
//end @win change
|
||||
|
||||
+ "s.QtyOnHand,s.DateLastInventory,s.M_StorageOnHand_UU "
|
||||
+ "FROM M_StorageOnHand s"
|
||||
+ " 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) ";
|
||||
|
@ -349,7 +338,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
throw new IllegalArgumentException("Not found M_Locator_ID=" + M_Locator_ID);
|
||||
//
|
||||
retValue = new MStorageOnHand (locator, M_Product_ID, M_AttributeSetInstance_ID);
|
||||
retValue.save(trxName);
|
||||
retValue.saveEx(trxName);
|
||||
s_log.fine("New " + retValue);
|
||||
return retValue;
|
||||
} // getCreate
|
||||
|
@ -442,7 +431,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
diffText.append(") -> ").append(storage.toString());
|
||||
s_log.fine(diffText.toString());
|
||||
if (storage0 != null)
|
||||
storage0.save(trxName); // No AttributeSetInstance (reserved/ordered)
|
||||
storage0.saveEx(trxName); // No AttributeSetInstance (reserved/ordered)
|
||||
return storage.save (trxName);
|
||||
}
|
||||
|
||||
|
@ -525,7 +514,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
//
|
||||
setQtyOnHand (Env.ZERO);
|
||||
|
||||
} // MStorage
|
||||
} // MStorageOnHand
|
||||
|
||||
/**
|
||||
* Load Constructor
|
||||
|
@ -536,7 +525,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
public MStorageOnHand (Properties ctx, ResultSet rs, String trxName)
|
||||
{
|
||||
super(ctx, rs, trxName);
|
||||
} // MStorage
|
||||
} // MStorageOnHand
|
||||
|
||||
/**
|
||||
* Full NEW Constructor
|
||||
|
@ -551,7 +540,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
setM_Locator_ID (locator.getM_Locator_ID());
|
||||
setM_Product_ID (M_Product_ID);
|
||||
setM_AttributeSetInstance_ID (M_AttributeSetInstance_ID);
|
||||
} // MStorage
|
||||
} // MStorageOnHand
|
||||
|
||||
/** Log */
|
||||
private static CLogger s_log = CLogger.getCLogger (MStorageOnHand.class);
|
||||
|
@ -640,18 +629,18 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
* @return
|
||||
*/
|
||||
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();
|
||||
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(" 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_Warehouse_ID);
|
||||
|
||||
// With ASI
|
||||
if (M_AttributeSetInstance_ID != 0) {
|
||||
sql.append(" AND M_AttributeSetInstance_ID=?");
|
||||
sql.append(" AND oh.M_AttributeSetInstance_ID=?");
|
||||
params.add(M_AttributeSetInstance_ID);
|
||||
}
|
||||
|
||||
|
@ -668,7 +657,7 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
*/
|
||||
public String toString()
|
||||
{
|
||||
StringBuffer sb = new StringBuffer("MStorage[")
|
||||
StringBuffer sb = new StringBuffer("MStorageOnHand[")
|
||||
.append("M_Locator_ID=").append(getM_Locator_ID())
|
||||
.append(",M_Product_ID=").append(getM_Product_ID())
|
||||
.append(",M_AttributeSetInstance_ID=").append(getM_AttributeSetInstance_ID())
|
||||
|
@ -681,4 +670,4 @@ public class MStorageOnHand extends X_M_StorageOnHand
|
|||
return sb.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;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.compiere.util.CLogMgt;
|
||||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
|
||||
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);
|
||||
|
||||
public MStorageReservation(Properties ctx, int M_StorageReservation_ID,
|
||||
String trxName) {
|
||||
super(ctx, M_StorageReservation_ID, trxName);
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public MStorageReservation(Properties ctx, ResultSet rs,
|
||||
String 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
|
||||
* @param ctx
|
||||
|
@ -74,25 +156,25 @@ public class MStorageReservation extends X_M_StorageReservation {
|
|||
|
||||
} // getOfProduct
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get Quantity Reserved of Warehouse
|
||||
* @param M_Product_ID
|
||||
* @param M_Warehouse_ID
|
||||
* @param M_AttributeSetInstance_ID
|
||||
* @param isSOTrx - true to get reserved, false to get ordered
|
||||
* @param trxName
|
||||
* @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>();
|
||||
StringBuffer sql = new StringBuffer();
|
||||
sql.append(" SELECT SUM(Qty) FROM M_StorageReservation oh")
|
||||
.append(" WHERE oh.M_Product_ID=? AND oh.M_Warehouse_ID=?")
|
||||
.append(" AND oh.IsSOTrx='Y'");
|
||||
sql.append(" SELECT SUM(Qty) FROM M_StorageReservation sr")
|
||||
.append(" WHERE sr.M_Product_ID=? AND sr.M_Warehouse_ID=?")
|
||||
.append(" AND sr.IsSOTrx=?");
|
||||
|
||||
params.add(M_Product_ID);
|
||||
params.add(M_Warehouse_ID);
|
||||
params.add(isSOTrx ? "Y" : "N");
|
||||
|
||||
// With ASI
|
||||
if (M_AttributeSetInstance_ID != 0) {
|
||||
|
@ -107,13 +189,6 @@ public class MStorageReservation extends X_M_StorageReservation {
|
|||
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.
|
||||
* 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)
|
||||
{
|
||||
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);
|
||||
return retValue;
|
||||
}
|
||||
|
||||
public BigDecimal getQtyOrdered() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
/**
|
||||
* Update Storage Info add.
|
||||
* 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() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
MStorageReservation storage0 = null;
|
||||
if (M_AttributeSetInstance_ID != reservationAttributeSetInstance_ID)
|
||||
{
|
||||
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.MCharge;
|
||||
import org.compiere.model.MClient;
|
||||
import org.compiere.model.MLocator;
|
||||
import org.compiere.model.MProduct;
|
||||
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());
|
||||
MStorageOnHand[] storages = MStorageOnHand.getWarehouse(getCtx(),
|
||||
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;
|
||||
for (int i = 0; i < storages.length; i++)
|
||||
{
|
||||
|
|
|
@ -512,7 +512,7 @@ public class InfoPAttribute extends CDialog
|
|||
// finish Instance Attributes
|
||||
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) "
|
||||
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
||||
sb.append(")");
|
||||
|
|
|
@ -1240,23 +1240,21 @@ public class InfoProduct extends Info implements ActionListener, ChangeListener
|
|||
|
||||
// Fill Storage Data
|
||||
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,";
|
||||
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,";
|
||||
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_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') "
|
||||
+ " 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=?";
|
||||
+ "WHERE M_Product_ID=?";
|
||||
if (m_M_Warehouse_ID != 0)
|
||||
sql += " AND l.M_Warehouse_ID=?";
|
||||
if (m_M_AttributeSetInstance_ID > 0)
|
||||
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)
|
||||
sql += " GROUP BY productAttribute(s.M_AttributeSetInstance_ID), w.Name, 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),"
|
||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||
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_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_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),
|
||||
};
|
||||
/** 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_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)";
|
||||
|
|
|
@ -456,7 +456,7 @@ public class VLocator extends JComponent
|
|||
sql.append(" AND (IsDefault='Y' ") // Default 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("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=?))");
|
||||
String finalSql = MRole.getDefault(Env.getCtx(), false).addAccessSQL(
|
||||
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),
|
||||
};
|
||||
/** 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_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)";
|
||||
|
|
|
@ -614,7 +614,7 @@ public class InfoPAttributePanel extends Window implements EventListener
|
|||
// finish Instance Attributes
|
||||
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) "
|
||||
+ "WHERE s.M_Product_ID=p.M_Product_ID");
|
||||
sb.append(")");
|
||||
|
|
|
@ -1453,7 +1453,7 @@ public class InfoProductPanel extends InfoPanel implements EventListener
|
|||
sql = "SELECT SUM(s.QtyOnHand), SUM(s.QtyReserved), SUM(s.QtyOrdered),"
|
||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||
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_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_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),"
|
||||
+ " productAttribute(s.M_AttributeSetInstance_ID), 0,";
|
||||
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_Warehouse w ON (l.M_Warehouse_ID=w.M_Warehouse_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),
|
||||
};
|
||||
/** 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_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)";
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.compiere.model.MMatchPO;
|
|||
import org.compiere.model.MOrderLine;
|
||||
import org.compiere.model.MRole;
|
||||
import org.compiere.model.MStorageOnHand;
|
||||
import org.compiere.model.MStorageReservation;
|
||||
import org.compiere.process.DocumentEngine;
|
||||
import org.compiere.util.CLogger;
|
||||
import org.compiere.util.DB;
|
||||
|
@ -491,11 +492,10 @@ public class Match
|
|||
success = true;
|
||||
// Correct Ordered Qty for Stocked Products (see MOrder.reserveStock / MInOut.processIt)
|
||||
if (sLine.getProduct() != null && sLine.getProduct().isStocked())
|
||||
success = MStorageOnHand.add (Env.getCtx(), sLine.getM_Warehouse_ID(),
|
||||
sLine.getM_Locator_ID(),
|
||||
success = MStorageReservation.add (Env.getCtx(), sLine.getM_Warehouse_ID(),
|
||||
sLine.getM_Product_ID(),
|
||||
sLine.getM_AttributeSetInstance_ID(), oLine.getM_AttributeSetInstance_ID(),
|
||||
null, trxName);
|
||||
qty.negate(), false, trxName);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
Loading…
Reference in New Issue