Fix [ 1915030 ] Validation in CalloutProductCategory must be done beforeSave
This commit is contained in:
parent
ddfad43b52
commit
5e02efd9cb
|
@ -1,5 +1,5 @@
|
|||
/******************************************************************************
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms version 2 of the GNU General Public License as published *
|
||||
|
@ -24,7 +24,7 @@ import java.util.logging.*;
|
|||
import org.compiere.util.*;
|
||||
|
||||
/**
|
||||
* Callout Emgine.
|
||||
* Callout Engine.
|
||||
*
|
||||
* @author Jorg Janke
|
||||
* @version $Id: CalloutEngine.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/******************************************************************************
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms version 2 of the GNU General Public License as published *
|
||||
|
@ -16,17 +16,7 @@
|
|||
*****************************************************************************/
|
||||
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.Vector;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.compiere.util.DB;
|
||||
import org.compiere.util.Env;
|
||||
|
||||
|
||||
/**
|
||||
* Product Category Callouts
|
||||
|
@ -51,97 +41,18 @@ public class CalloutProductCategory extends CalloutEngine
|
|||
if (isCalloutActive() || value == null)
|
||||
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);
|
||||
if (productCategoryId == null)
|
||||
productCategoryId = new Integer(0);
|
||||
ResultSet rs = null;
|
||||
Statement stmt = 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 {
|
||||
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);
|
||||
|
||||
if (productCategoryId.intValue() > 0) {
|
||||
MProductCategory pc = new MProductCategory(ctx, productCategoryId.intValue(), null);
|
||||
pc.setM_Product_Category_Parent_ID(((Integer) value).intValue());
|
||||
if (pc.hasLoopInTree())
|
||||
return "ProductCategoryLoopDetected";
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
log.log(Level.SEVERE, sql, e);
|
||||
return e.getMessage();
|
||||
}
|
||||
finally
|
||||
{
|
||||
DB.close(rs, stmt);
|
||||
rs = null; stmt = null;
|
||||
}
|
||||
|
||||
return "";
|
||||
} // 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
|
|
@ -1,5 +1,5 @@
|
|||
/******************************************************************************
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms version 2 of the GNU General Public License as published *
|
||||
|
@ -19,6 +19,7 @@ package org.compiere.model;
|
|||
import java.sql.*;
|
||||
import java.util.*;
|
||||
import java.util.logging.*;
|
||||
|
||||
import org.compiere.util.*;
|
||||
|
||||
/**
|
||||
|
@ -29,6 +30,12 @@ import org.compiere.util.*;
|
|||
*/
|
||||
public class MProductCategory extends X_M_Product_Category
|
||||
{
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -1290361229726779892L;
|
||||
|
||||
|
||||
/**
|
||||
* Get from Cache
|
||||
* @param ctx context
|
||||
|
@ -140,6 +147,21 @@ public class MProductCategory extends X_M_Product_Category
|
|||
super(ctx, rs, trxName);
|
||||
} // 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
|
||||
* @param newRecord new
|
||||
|
@ -172,4 +194,103 @@ public class MProductCategory extends X_M_Product_Category
|
|||
return MMPOLICY_FiFo.equals(getMMPolicy());
|
||||
} // isFiFo
|
||||
|
||||
} // MProductCategory
|
||||
|
||||
/**
|
||||
* 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
|
Loading…
Reference in New Issue