Fix [ 1915030 ] Validation in CalloutProductCategory must be done beforeSave
This commit is contained in:
parent
ddfad43b52
commit
5e02efd9cb
|
@ -24,7 +24,7 @@ import java.util.logging.*;
|
||||||
import org.compiere.util.*;
|
import org.compiere.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callout Emgine.
|
* Callout Engine.
|
||||||
*
|
*
|
||||||
* @author Jorg Janke
|
* @author Jorg Janke
|
||||||
* @version $Id: CalloutEngine.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
|
* @version $Id: CalloutEngine.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
|
||||||
|
|
|
@ -16,17 +16,7 @@
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
package org.compiere.model;
|
package org.compiere.model;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.Vector;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
|
|
||||||
import org.compiere.util.DB;
|
|
||||||
import org.compiere.util.Env;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Product Category Callouts
|
* Product Category Callouts
|
||||||
|
@ -51,97 +41,18 @@ public class CalloutProductCategory extends CalloutEngine
|
||||||
if (isCalloutActive() || value == null)
|
if (isCalloutActive() || value == null)
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
// get values
|
|
||||||
Integer newParentCategoryId = (Integer) mTab.getValue(MProductCategory.COLUMNNAME_M_Product_Category_Parent_ID);
|
|
||||||
Integer productCategoryId = (Integer) mTab.getValue(MProductCategory.COLUMNNAME_M_Product_Category_ID);
|
Integer productCategoryId = (Integer) mTab.getValue(MProductCategory.COLUMNNAME_M_Product_Category_ID);
|
||||||
if (productCategoryId == null)
|
if (productCategoryId == null)
|
||||||
productCategoryId = new Integer(0);
|
productCategoryId = new Integer(0);
|
||||||
ResultSet rs = null;
|
|
||||||
Statement stmt = null;
|
if (productCategoryId.intValue() > 0) {
|
||||||
String sql = " SELECT M_Product_Category_ID, M_Product_Category_Parent_ID FROM M_Product_Category";
|
MProductCategory pc = new MProductCategory(ctx, productCategoryId.intValue(), null);
|
||||||
final Vector<SimpleTreeNode> categories = new Vector<SimpleTreeNode>(100);
|
pc.setM_Product_Category_Parent_ID(((Integer) value).intValue());
|
||||||
try {
|
if (pc.hasLoopInTree())
|
||||||
stmt = DB.createStatement();
|
|
||||||
rs = stmt.executeQuery(sql);
|
|
||||||
while (rs.next()) {
|
|
||||||
if(rs.getInt(1)==productCategoryId.intValue()) {
|
|
||||||
categories.add(new SimpleTreeNode(rs.getInt(1), newParentCategoryId));
|
|
||||||
}
|
|
||||||
categories.add(new SimpleTreeNode(rs.getInt(1), rs.getInt(2)));
|
|
||||||
}
|
|
||||||
if (hasLoop(newParentCategoryId, categories, productCategoryId.intValue())) {
|
|
||||||
mTab.setValue(MProductCategory.COLUMNNAME_M_Product_Category_Parent_ID, oldValue);
|
|
||||||
return "ProductCategoryLoopDetected";
|
return "ProductCategoryLoopDetected";
|
||||||
}
|
}
|
||||||
} catch (SQLException e) {
|
|
||||||
log.log(Level.SEVERE, sql, e);
|
|
||||||
return e.getMessage();
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
DB.close(rs, stmt);
|
|
||||||
rs = null; stmt = null;
|
|
||||||
}
|
|
||||||
return "";
|
return "";
|
||||||
} // testForLoop
|
} // testForLoop
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Recursive search for parent nodes - climbes the to the root.
|
|
||||||
* If there is a circle there is no root but it comes back to the start node.
|
|
||||||
* @param parentCategoryId
|
|
||||||
* @param categories
|
|
||||||
* @param loopIndicatorId
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
private boolean hasLoop(int parentCategoryId, Vector<SimpleTreeNode> categories, int loopIndicatorId) {
|
|
||||||
final Iterator iter = categories.iterator();
|
|
||||||
boolean ret = false;
|
|
||||||
while (iter.hasNext()) {
|
|
||||||
SimpleTreeNode node = (SimpleTreeNode) iter.next();
|
|
||||||
if(node.getNodeId()==parentCategoryId){
|
|
||||||
if (node.getParentId()==0) {
|
|
||||||
//root node, all fine
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(node.getNodeId()==loopIndicatorId){
|
|
||||||
//loop found
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
ret = hasLoop(node.getParentId(), categories, loopIndicatorId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
} //hasLoop
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Simple class for tree nodes.
|
|
||||||
* @author Karsten Thiemann, kthiemann@adempiere.org
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private class SimpleTreeNode {
|
|
||||||
/** id of the node */
|
|
||||||
private int nodeId;
|
|
||||||
/** id of the nodes parent */
|
|
||||||
private int parentId;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor.
|
|
||||||
* @param nodeId
|
|
||||||
* @param parentId
|
|
||||||
*/
|
|
||||||
public SimpleTreeNode(int nodeId, int parentId) {
|
|
||||||
this.nodeId = nodeId;
|
|
||||||
this.parentId = parentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNodeId() {
|
|
||||||
return nodeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getParentId() {
|
|
||||||
return parentId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // CalloutProductCategory
|
} // CalloutProductCategory
|
|
@ -19,6 +19,7 @@ package org.compiere.model;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.logging.*;
|
import java.util.logging.*;
|
||||||
|
|
||||||
import org.compiere.util.*;
|
import org.compiere.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,6 +30,12 @@ import org.compiere.util.*;
|
||||||
*/
|
*/
|
||||||
public class MProductCategory extends X_M_Product_Category
|
public class MProductCategory extends X_M_Product_Category
|
||||||
{
|
{
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private static final long serialVersionUID = -1290361229726779892L;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get from Cache
|
* Get from Cache
|
||||||
* @param ctx context
|
* @param ctx context
|
||||||
|
@ -140,6 +147,21 @@ public class MProductCategory extends X_M_Product_Category
|
||||||
super(ctx, rs, trxName);
|
super(ctx, rs, trxName);
|
||||||
} // MProductCategory
|
} // MProductCategory
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Before Save
|
||||||
|
* @param newRecord new
|
||||||
|
* @return true
|
||||||
|
*/
|
||||||
|
protected boolean beforeSave (boolean newRecord)
|
||||||
|
{
|
||||||
|
if (hasLoopInTree()) {
|
||||||
|
log.saveError("Error", Msg.getMsg(getCtx(), "ProductCategoryLoopDetected"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} // beforeSave
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After Save
|
* After Save
|
||||||
* @param newRecord new
|
* @param newRecord new
|
||||||
|
@ -172,4 +194,103 @@ public class MProductCategory extends X_M_Product_Category
|
||||||
return MMPOLICY_FiFo.equals(getMMPolicy());
|
return MMPOLICY_FiFo.equals(getMMPolicy());
|
||||||
} // isFiFo
|
} // isFiFo
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loop detection of product category tree.
|
||||||
|
* @param productCategoryId
|
||||||
|
* @param newParentCategoryId
|
||||||
|
*
|
||||||
|
* @param newParentCategoryId New Parent Category
|
||||||
|
* @return "" or error message
|
||||||
|
*/
|
||||||
|
public boolean hasLoopInTree ()
|
||||||
|
{
|
||||||
|
int productCategoryId = getM_Product_Category_ID();
|
||||||
|
int newParentCategoryId = getM_Product_Category_Parent_ID();
|
||||||
|
// get values
|
||||||
|
ResultSet rs = null;
|
||||||
|
PreparedStatement pstmt = null;
|
||||||
|
String sql = " SELECT M_Product_Category_ID, M_Product_Category_Parent_ID FROM M_Product_Category";
|
||||||
|
final Vector<SimpleTreeNode> categories = new Vector<SimpleTreeNode>(100);
|
||||||
|
try {
|
||||||
|
pstmt = DB.prepareStatement(sql, null);
|
||||||
|
rs = pstmt.executeQuery();
|
||||||
|
while (rs.next()) {
|
||||||
|
if (rs.getInt(1) == productCategoryId)
|
||||||
|
categories.add(new SimpleTreeNode(rs.getInt(1), newParentCategoryId));
|
||||||
|
categories.add(new SimpleTreeNode(rs.getInt(1), rs.getInt(2)));
|
||||||
|
}
|
||||||
|
if (hasLoop(newParentCategoryId, categories, productCategoryId))
|
||||||
|
return true;
|
||||||
|
} catch (SQLException e) {
|
||||||
|
s_log.log(Level.SEVERE, sql, e);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DB.close(rs, pstmt);
|
||||||
|
rs = null; pstmt = null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
} // hasLoopInTree
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive search for parent nodes - climbs the to the root.
|
||||||
|
* If there is a circle there is no root but it comes back to the start node.
|
||||||
|
* @param parentCategoryId
|
||||||
|
* @param categories
|
||||||
|
* @param loopIndicatorId
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private boolean hasLoop(int parentCategoryId, Vector<SimpleTreeNode> categories, int loopIndicatorId) {
|
||||||
|
final Iterator<SimpleTreeNode> iter = categories.iterator();
|
||||||
|
boolean ret = false;
|
||||||
|
while (iter.hasNext()) {
|
||||||
|
SimpleTreeNode node = (SimpleTreeNode) iter.next();
|
||||||
|
if(node.getNodeId()==parentCategoryId){
|
||||||
|
if (node.getParentId()==0) {
|
||||||
|
//root node, all fine
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(node.getNodeId()==loopIndicatorId){
|
||||||
|
//loop found
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
ret = hasLoop(node.getParentId(), categories, loopIndicatorId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
} //hasLoop
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple class for tree nodes.
|
||||||
|
* @author Karsten Thiemann, kthiemann@adempiere.org
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private class SimpleTreeNode {
|
||||||
|
/** id of the node */
|
||||||
|
private int nodeId;
|
||||||
|
/** id of the nodes parent */
|
||||||
|
private int parentId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
* @param nodeId
|
||||||
|
* @param parentId
|
||||||
|
*/
|
||||||
|
public SimpleTreeNode(int nodeId, int parentId) {
|
||||||
|
this.nodeId = nodeId;
|
||||||
|
this.parentId = parentId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getNodeId() {
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getParentId() {
|
||||||
|
return parentId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // MProductCategory
|
} // MProductCategory
|
Loading…
Reference in New Issue