IDEMPIERE-385 Resolve M_Storage locking and data consistency / lock storage record being updated

This commit is contained in:
Carlos Ruiz 2012-11-28 10:12:56 -05:00
parent 1ec9ea4a21
commit 1c0b1ebd9e
12 changed files with 73 additions and 122 deletions

View File

@ -1,4 +1,4 @@
|||14:59:04 Tue, Nov 27, 2012|
|||01:35:08 mié, nov 28, 2012|
|CommonTests.CreateMaterialReceipt||01:36:56 mar, abr 03, 2012|
|CommonTests.CreateProductPrice||01:29:57 mar, abr 03, 2012|
|AvgCostSuite.BasicTest||01:18:34 mar, abr 03, 2012|

View File

@ -2,7 +2,7 @@ Define the global path:
Where to find the fixtures classes: ( i.e. /home/hengsin/workspace/idempiere/fitnesse/bin )
!define fitnesse_home {/home/hengsin/workspace/idempiere/fitnesse}
!define fitnesse_home {/home/carlos/hgAdempiere/localosgi/fitnesse}
!path ${fitnesse_home}/fitnesse.jar:${fitnesse_home}/lib/*.jar:${fitnesse_home}/bin
@ -16,7 +16,7 @@ There are some important variables here:
This variables can be redefined specifically at page level.
!define TEST_RUNNER {fitnesse.client.FitServerServletInvoker}
!define COMMAND_PATTERN {java -Xms32m -Xmx512m -DLOG4J_LEVEL=CONFIG -cp %p %m http://localhost:8080/fitnesse/FitServlet}
!define COMMAND_PATTERN {java -Xms32m -Xmx512m -DLOG4J_LEVEL=CONFIG -cp %p %m http://localhost:8082/fitnesse/FitServlet}
To enable remote debugging the tests will stop until you connect remotely via eclipse using RemoteADempiereFitnesse.launch

View File

@ -158,7 +158,7 @@ public class M_Production_Run extends SvrProcess {
if (!MStorageOnHand.add(getCtx(), locator.getM_Warehouse_ID(),
locator.getM_Locator_ID(),
pline.getM_Product_ID(),
pline.getM_AttributeSetInstance_ID(), 0 ,
pline.getM_AttributeSetInstance_ID(),
MovementQty,
get_TrxName()))
{

View File

@ -1356,7 +1356,7 @@ public class MInOut extends X_M_InOut implements DocAction
if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(),
sLine.getM_Locator_ID(),
sLine.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
ma.getM_AttributeSetInstance_ID(),
QtyMA,
get_TrxName()))
{
@ -1438,7 +1438,7 @@ public class MInOut extends X_M_InOut implements DocAction
if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(),
sLine.getM_Locator_ID(),
sLine.getM_Product_ID(),
sLine.getM_AttributeSetInstance_ID(), reservationAttributeSetInstance_ID,
sLine.getM_AttributeSetInstance_ID(),
Qty, get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");

View File

@ -440,7 +440,7 @@ public class MInventory extends X_M_Inventory implements DocAction
if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(),
line.getM_Locator_ID(),
line.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), 0,
ma.getM_AttributeSetInstance_ID(),
QtyMA.negate(), get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");
@ -491,7 +491,7 @@ public class MInventory extends X_M_Inventory implements DocAction
if (!MStorageOnHand.add(getCtx(), getM_Warehouse_ID(),
line.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), 0,
line.getM_AttributeSetInstance_ID(),
qtyDiff,get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");

View File

@ -403,7 +403,7 @@ public class MMovement extends X_M_Movement implements DocAction
if (!MStorageOnHand.add(getCtx(),locator.getM_Warehouse_ID(),
line.getM_Locator_ID(),
line.getM_Product_ID(),
ma.getM_AttributeSetInstance_ID(), 0,
ma.getM_AttributeSetInstance_ID(),
ma.getMovementQty().negate(), get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");
@ -421,7 +421,7 @@ public class MMovement extends X_M_Movement implements DocAction
if (!MStorageOnHand.add(getCtx(),locator.getM_Warehouse_ID(),
line.getM_LocatorTo_ID(),
line.getM_Product_ID(),
M_AttributeSetInstanceTo_ID, 0,
M_AttributeSetInstanceTo_ID,
ma.getMovementQty(), get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");
@ -461,7 +461,7 @@ public class MMovement extends X_M_Movement implements DocAction
if (!MStorageOnHand.add(getCtx(),locator.getM_Warehouse_ID(),
line.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), 0,
line.getM_AttributeSetInstance_ID(),
line.getMovementQty().negate(), get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");
@ -473,7 +473,7 @@ public class MMovement extends X_M_Movement implements DocAction
if (!MStorageOnHand.add(getCtx(),locator.getM_Warehouse_ID(),
line.getM_LocatorTo_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstanceTo_ID(), 0,
line.getM_AttributeSetInstanceTo_ID(),
line.getMovementQty(), get_TrxName()))
{
String lastError = CLogger.retrieveErrorString("");

View File

@ -164,7 +164,7 @@ public class MProjectIssue extends X_C_ProjectIssue
//
MLocator loc = MLocator.get(getCtx(), getM_Locator_ID());
if (MStorageOnHand.add(getCtx(), loc.getM_Warehouse_ID(), getM_Locator_ID(),
getM_Product_ID(), getM_AttributeSetInstance_ID(), getM_AttributeSetInstance_ID(),
getM_Product_ID(), getM_AttributeSetInstance_ID(),
getMovementQty().negate(), get_TrxName()))
{
if (mTrx.save(get_TrxName()))

View File

@ -358,16 +358,15 @@ public class MStorageOnHand extends X_M_StorageOnHand
* @return true if updated
*/
public static boolean add (Properties ctx, int M_Warehouse_ID, int M_Locator_ID,
int M_Product_ID, int M_AttributeSetInstance_ID, int reservationAttributeSetInstance_ID,
int M_Product_ID, int M_AttributeSetInstance_ID,
BigDecimal diffQtyOnHand, String trxName)
{
MStorageOnHand storage = null;
StringBuffer diffText = new StringBuffer("(");
if (diffQtyOnHand == null || diffQtyOnHand.signum() == 0)
return true;
// Get Storage
if (storage == null)
storage = getCreate (ctx, M_Locator_ID,
M_Product_ID, M_AttributeSetInstance_ID, trxName);
MStorageOnHand storage = getCreate (ctx, M_Locator_ID, M_Product_ID, M_AttributeSetInstance_ID, trxName);
DB.getDatabase().forUpdate(storage, 120);
// Verify
if (storage.getM_Locator_ID() != M_Locator_ID
&& storage.getM_Product_ID() != M_Product_ID
@ -378,64 +377,12 @@ public class MStorageOnHand extends X_M_StorageOnHand
return false;
}
// CarlosRuiz - globalqss - Fix [ 1725383 ] QtyOrdered wrongly updated
MProduct prd = new MProduct(ctx, M_Product_ID, trxName);
if (prd.getM_AttributeSet_ID() == 0) {
// Product doesn't manage attribute set, always reserved with 0
reservationAttributeSetInstance_ID = 0;
}
//
MStorageOnHand storage0 = null;
if (M_AttributeSetInstance_ID != reservationAttributeSetInstance_ID)
{
storage0 = get(ctx, M_Locator_ID,
M_Product_ID, reservationAttributeSetInstance_ID, trxName);
if (storage0 == null) // create if not existing - should not happen
{
MWarehouse wh = MWarehouse.get(ctx, M_Warehouse_ID);
int xM_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
storage0 = getCreate (ctx, xM_Locator_ID,
M_Product_ID, reservationAttributeSetInstance_ID, trxName);
}
}
boolean changed = false;
if (diffQtyOnHand != null && diffQtyOnHand.signum() != 0)
{
storage.setQtyOnHand (storage.getQtyOnHand().add (diffQtyOnHand));
diffText.append("OnHand=").append(diffQtyOnHand);
changed = true;
}
/*//@win commented out
if (diffQtyReserved != null && diffQtyReserved.signum() != 0)
{
if (storage0 == null)
storage.setQtyReserved (storage.getQtyReserved().add (diffQtyReserved));
else
storage0.setQtyReserved (storage0.getQtyReserved().add (diffQtyReserved));
diffText.append(" Reserved=").append(diffQtyReserved);
changed = true;
}
if (diffQtyOrdered != null && diffQtyOrdered.signum() != 0)
{
if (storage0 == null)
storage.setQtyOrdered (storage.getQtyOrdered().add (diffQtyOrdered));
else
storage0.setQtyOrdered (storage0.getQtyOrdered().add (diffQtyOrdered));
diffText.append(" Ordered=").append(diffQtyOrdered);
changed = true;
}
*/
if (changed)
{
diffText.append(") -> ").append(storage.toString());
if (s_log.isLoggable(Level.FINE)) {
StringBuilder diffText = new StringBuilder("(OnHand=").append(diffQtyOnHand).append(") -> ").append(storage.toString());
s_log.fine(diffText.toString());
if (storage0 != null)
storage0.saveEx(trxName); // No AttributeSetInstance (reserved/ordered)
return storage.save (trxName);
}
return true;
return storage.save (trxName);
} // add

View File

@ -225,6 +225,9 @@ public class MStorageReservation extends X_M_StorageReservation {
int M_Product_ID, int M_AttributeSetInstance_ID, int reservationAttributeSetInstance_ID,
BigDecimal diffQty, boolean isSOTrx, String trxName)
{
if (diffQty == null || diffQty.signum() == 0)
return true;
/* 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()) {
@ -233,14 +236,14 @@ public class MStorageReservation extends X_M_StorageReservation {
M_AttributeSetInstance_ID = 0;
}
//
MStorageReservation storage = null;
StringBuffer diffText = new StringBuffer("(");
if (M_AttributeSetInstance_ID != reservationAttributeSetInstance_ID) {
M_AttributeSetInstance_ID = reservationAttributeSetInstance_ID;
}
// Get Storage
if (storage == null)
storage = getCreate (ctx, M_Warehouse_ID,
MStorageReservation storage = getCreate (ctx, M_Warehouse_ID,
M_Product_ID, M_AttributeSetInstance_ID, isSOTrx, trxName);
DB.getDatabase().forUpdate(storage, 120);
// Verify
if (storage.getM_Warehouse_ID() != M_Warehouse_ID
&& storage.getM_Product_ID() != M_Product_ID
@ -251,37 +254,12 @@ public class MStorageReservation extends X_M_StorageReservation {
return false;
}
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());
if (s_log.isLoggable(Level.FINE)) {
StringBuilder diffText = new StringBuilder("(Qty=").append(diffQty).append(") -> ").append(storage.toString());
s_log.fine(diffText.toString());
if (storage0 != null)
storage0.saveEx(trxName); // No AttributeSetInstance
return storage.save (trxName);
}
return true;
return storage.save (trxName);
} // add
/**

View File

@ -885,7 +885,7 @@ public class MDDOrder extends X_DD_Order implements DocAction
// Update Storage
if (!MStorageOnHand.add(getCtx(), locator_to.getM_Warehouse_ID(), locator_to.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstance_ID(), line.getM_AttributeSetInstance_ID(),
line.getM_AttributeSetInstance_ID(),
Env.ZERO, get_TrxName()))
{
throw new AdempiereException();
@ -893,7 +893,7 @@ public class MDDOrder extends X_DD_Order implements DocAction
if (!MStorageOnHand.add(getCtx(), locator_from.getM_Warehouse_ID(), locator_from.getM_Locator_ID(),
line.getM_Product_ID(),
line.getM_AttributeSetInstanceTo_ID(), line.getM_AttributeSetInstance_ID(),
line.getM_AttributeSetInstanceTo_ID(),
Env.ZERO, get_TrxName()))
{
throw new AdempiereException();

View File

@ -1255,10 +1255,21 @@ public class DB_Oracle implements AdempiereDatabase
for(int i = 0; i < keyColumns.length; i++) {
if (i > 0)
sqlBuffer.append(" AND ");
sqlBuffer.append(keyColumns[i]).append(" = ? ");
sqlBuffer.append(keyColumns[i]).append("=?");
}
sqlBuffer.append(" FOR UPDATE WAIT ").append((timeout > 0 ? timeout : LOCK_TIME_OUT));
Object[] parameters = new Object[keyColumns.length];
for(int i = 0; i < keyColumns.length; i++) {
Object parameter = po.get_Value(keyColumns[i]);
if (parameter != null && parameter instanceof Boolean) {
if ((Boolean) parameter)
parameter = "Y";
else
parameter = "N";
}
parameters[i] = parameter;
}
sqlBuffer.append(" FOR UPDATE ");
sqlBuffer.append(" WAIT ").append((timeout > 0 ? timeout : LOCK_TIME_OUT));
PreparedStatement stmt = null;
ResultSet rs = null;
@ -1266,7 +1277,7 @@ public class DB_Oracle implements AdempiereDatabase
stmt = DB.prepareStatement(sqlBuffer.toString(),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE, po.get_TrxName());
for(int i = 0; i < keyColumns.length; i++) {
stmt.setObject(i+1, po.get_Value(keyColumns[i]));
stmt.setObject(i+1, parameters[i]);
}
rs = stmt.executeQuery();
if (rs.next()) {
@ -1276,6 +1287,7 @@ public class DB_Oracle implements AdempiereDatabase
}
} catch (Exception e) {
log.log(Level.INFO, e.getLocalizedMessage(), e);
throw new DBException("Could not lock record for " + po.toString() + " caused by " + e.getLocalizedMessage());
} finally {
DB.close(rs, stmt);
}

View File

@ -994,9 +994,22 @@ public class DB_PostgreSQL implements AdempiereDatabase
for(int i = 0; i < keyColumns.length; i++) {
if (i > 0)
sqlBuffer.append(" AND ");
sqlBuffer.append(keyColumns[i]).append(" = ? ");
sqlBuffer.append(keyColumns[i]).append("=?");
}
sqlBuffer.append(" FOR UPDATE ");
Object[] parameters = new Object[keyColumns.length];
for(int i = 0; i < keyColumns.length; i++) {
Object parameter = po.get_Value(keyColumns[i]);
if (parameter != null && parameter instanceof Boolean) {
if ((Boolean) parameter)
parameter = "Y";
else
parameter = "N";
}
parameters[i] = parameter;
}
PreparedStatement stmt = null;
ResultSet rs = null;
int currentTimeout = -1;
@ -1004,7 +1017,7 @@ public class DB_PostgreSQL implements AdempiereDatabase
stmt = DB.prepareStatement(sqlBuffer.toString(),
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE, po.get_TrxName());
for(int i = 0; i < keyColumns.length; i++) {
stmt.setObject(i+1, po.get_Value(keyColumns[i]));
stmt.setObject(i+1, parameters[i]);
}
currentTimeout = setStatementTimeout(stmt.getConnection(), (timeout > 0 ? timeout : LOCK_TIME_OUT));
@ -1016,6 +1029,7 @@ public class DB_PostgreSQL implements AdempiereDatabase
}
} catch (Exception e) {
log.log(Level.INFO, e.getLocalizedMessage(), e);
throw new DBException("Could not lock record for " + po.toString() + " caused by " + e.getLocalizedMessage());
} finally {
try {
setStatementTimeout(stmt.getConnection(), currentTimeout);