Fix [ 1915030 ] Validation in CalloutProductCategory must be done beforeSave

This commit is contained in:
Carlos Ruiz 2008-03-15 23:48:59 +00:00
parent ddfad43b52
commit 5e02efd9cb
3 changed files with 133 additions and 101 deletions

View File

@ -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 $

View File

@ -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

View File

@ -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