[ 1741750 ] Atomic Workflow Activities + Making WFs more Predictable

This commit is contained in:
Heng Sin Low 2007-08-13 07:18:19 +00:00
parent 7ddb37ce99
commit c1bfcd4d66
4 changed files with 69 additions and 22 deletions

View File

@ -654,19 +654,35 @@ public class MUser extends X_AD_User
return m_roles; return m_roles;
ArrayList<MRole> list = new ArrayList<MRole>(); ArrayList<MRole> list = new ArrayList<MRole>();
// 2007-06-08, matthiasO.
// Extension of sql query so that not only roles with org acces for this user
// are found but also roles which delegate org access to the user level where
// this user has access to the org in question
String sql = "SELECT * FROM AD_Role r " String sql = "SELECT * FROM AD_Role r "
+ "WHERE r.IsActive='Y'" + "WHERE r.IsActive='Y'"
+ " AND EXISTS (SELECT * FROM AD_Role_OrgAccess ro"
+ " WHERE r.AD_Role_ID=ro.AD_Role_ID AND ro.IsActive='Y' AND ro.AD_Org_ID=?)"
+ " AND EXISTS (SELECT * FROM AD_User_Roles ur" + " AND EXISTS (SELECT * FROM AD_User_Roles ur"
+ " WHERE r.AD_Role_ID=ur.AD_Role_ID AND ur.IsActive='Y' AND ur.AD_User_ID=?) " + " WHERE r.AD_Role_ID=ur.AD_Role_ID AND ur.IsActive='Y' AND ur.AD_User_ID=?) "
+ " AND ("
+ " ("
+ " r.IsUseUserOrgAccess <> 'Y'"
+ " AND EXISTS (SELECT * FROM AD_Role_OrgAccess ro"
+ " WHERE r.AD_Role_ID=ro.AD_Role_ID AND ro.IsActive='Y' AND ro.AD_Org_ID=?)"
+ " ) OR "
+ " ("
+ " r.IsUseUserOrgAccess = 'Y'"
+ " AND EXISTS (SELECT * FROM AD_User_OrgAccess uo"
+ " WHERE uo.AD_User_ID=? AND uo.IsActive='Y' AND uo.AD_Org_ID=?)"
+ " )"
+ " ) "
+ "ORDER BY AD_Role_ID"; + "ORDER BY AD_Role_ID";
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
try try
{ {
pstmt = DB.prepareStatement (sql, get_TrxName()); pstmt = DB.prepareStatement (sql, get_TrxName());
pstmt.setInt (1, AD_Org_ID); pstmt.setInt (1, getAD_User_ID());
pstmt.setInt (2, getAD_User_ID()); pstmt.setInt (2, AD_Org_ID);
pstmt.setInt (3, getAD_User_ID());
pstmt.setInt (4, AD_Org_ID);
ResultSet rs = pstmt.executeQuery (); ResultSet rs = pstmt.executeQuery ();
while (rs.next ()) while (rs.next ())
list.add (new MRole(getCtx(), rs, get_TrxName())); list.add (new MRole(getCtx(), rs, get_TrxName()));

View File

@ -236,7 +236,8 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
// Inform Process // Inform Process
if (m_process == null) if (m_process == null)
m_process = new MWFProcess (getCtx(), getAD_WF_Process_ID(), null); m_process = new MWFProcess (getCtx(), getAD_WF_Process_ID(),
m_trx == null ? null : m_trx.getTrxName());
m_process.checkActivities(m_trx == null ? null : m_trx.getTrxName()); m_process.checkActivities(m_trx == null ? null : m_trx.getTrxName());
} }
else else
@ -674,7 +675,8 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
} }
} }
} // No Supervisor } // No Supervisor
//ownDocument should always be false for the next user
ownDocument = false;
} // while there is a user to approve } // while there is a user to approve
log.fine("No user found"); log.fine("No user found");
@ -755,7 +757,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
addTextMsg(e); addTextMsg(e);
setWFState (StateEngine.STATE_Terminated); // unlocks setWFState (StateEngine.STATE_Terminated); // unlocks
// Set Document Status // Set Document Status
if (m_po != null && m_docStatus != null) if (m_po != null && m_po instanceof DocAction && m_docStatus != null)
{ {
m_po.load(null); m_po.load(null);
DocAction doc = (DocAction)m_po; DocAction doc = (DocAction)m_po;
@ -855,6 +857,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
log.fine("Report:AD_Process_ID=" + m_node.getAD_Process_ID()); log.fine("Report:AD_Process_ID=" + m_node.getAD_Process_ID());
// Process // Process
MProcess process = MProcess.get(getCtx(), m_node.getAD_Process_ID()); MProcess process = MProcess.get(getCtx(), m_node.getAD_Process_ID());
process.set_TrxName(trx != null ? trx.getTrxName() : null);
if (!process.isReport() || process.getAD_ReportView_ID() == 0) if (!process.isReport() || process.getAD_ReportView_ID() == 0)
throw new IllegalStateException("Not a Report AD_Process_ID=" + m_node.getAD_Process_ID()); throw new IllegalStateException("Not a Report AD_Process_ID=" + m_node.getAD_Process_ID());
// //
@ -863,6 +866,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
pi.setAD_User_ID(getAD_User_ID()); pi.setAD_User_ID(getAD_User_ID());
pi.setAD_Client_ID(getAD_Client_ID()); pi.setAD_Client_ID(getAD_Client_ID());
MPInstance pInstance = new MPInstance(process, getRecord_ID()); MPInstance pInstance = new MPInstance(process, getRecord_ID());
pInstance.set_TrxName(trx != null ? trx.getTrxName() : null);
fillParameter(pInstance, trx); fillParameter(pInstance, trx);
pi.setAD_PInstance_ID(pInstance.getAD_PInstance_ID()); pi.setAD_PInstance_ID(pInstance.getAD_PInstance_ID());
// Report // Report
@ -937,7 +941,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
+ " to " + value); + " to " + value);
MColumn column = m_node.getColumn(); MColumn column = m_node.getColumn();
int dt = column.getAD_Reference_ID(); int dt = column.getAD_Reference_ID();
return setVariable (value, dt, null); return setVariable (value, dt, null, trx);
} // SetVariable } // SetVariable
/****** TODO Start WF Instance ******/ /****** TODO Start WF Instance ******/
@ -953,7 +957,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
log.fine("UserChoice:AD_Column_ID=" + m_node.getAD_Column_ID()); log.fine("UserChoice:AD_Column_ID=" + m_node.getAD_Column_ID());
// Approval // Approval
if (m_node.isUserApproval() if (m_node.isUserApproval()
&& getPO() instanceof DocAction) && getPO(trx) instanceof DocAction)
{ {
DocAction doc = (DocAction)m_po; DocAction doc = (DocAction)m_po;
boolean autoApproval = false; boolean autoApproval = false;
@ -1011,10 +1015,10 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
* @return true if set * @return true if set
* @throws Exception if error * @throws Exception if error
*/ */
private boolean setVariable(String value, int displayType, String textMsg) throws Exception private boolean setVariable(String value, int displayType, String textMsg, Trx trx) throws Exception
{ {
m_newValue = null; m_newValue = null;
getPO(); getPO(trx);
if (m_po == null) if (m_po == null)
throw new Exception("Persistent Object not found - AD_Table_ID=" throw new Exception("Persistent Object not found - AD_Table_ID="
+ getAD_Table_ID() + ", Record_ID=" + getRecord_ID()); + getAD_Table_ID() + ", Record_ID=" + getRecord_ID());
@ -1030,7 +1034,7 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
dbValue = value; dbValue = value;
m_po.set_ValueOfColumn(getNode().getAD_Column_ID(), dbValue); m_po.set_ValueOfColumn(getNode().getAD_Column_ID(), dbValue);
m_po.save(); m_po.save();
if (!dbValue.equals(m_po.get_ValueOfColumn(getNode().getAD_Column_ID()))) if (dbValue != null && !dbValue.equals(m_po.get_ValueOfColumn(getNode().getAD_Column_ID())))
throw new Exception("Persistent Object not updated - AD_Table_ID=" throw new Exception("Persistent Object not updated - AD_Table_ID="
+ getAD_Table_ID() + ", Record_ID=" + getRecord_ID() + getAD_Table_ID() + ", Record_ID=" + getRecord_ID()
+ " - Should=" + value + ", Is=" + m_po.get_ValueOfColumn(m_node.getAD_Column_ID())); + " - Should=" + value + ", Is=" + m_po.get_ValueOfColumn(m_node.getAD_Column_ID()));
@ -1056,6 +1060,19 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
String textMsg) throws Exception String textMsg) throws Exception
{ {
// Check if user approves own document when a role is reponsible // Check if user approves own document when a role is reponsible
/*
* 2007-06-08, matthiasO.
* The following sequence makes sure that only users in roles which
* have the 'Approve own document flag' set can set the user choice
* of 'Y' (approve) or 'N' (reject).
* IMHO this is against the meaning of 'Approve own document': Why
* should a user who is faced with the task of approving documents
* generally be required to have the ability to approve his OWN
* documents? If the document to approve really IS his own document
* this will be respected when trying to find an approval user in
* the call to getApprovalUser(...) below.
*/
/*
if (getNode().isUserApproval() && getPO() instanceof DocAction) if (getNode().isUserApproval() && getPO() instanceof DocAction)
{ {
DocAction doc = (DocAction)m_po; DocAction doc = (DocAction)m_po;
@ -1077,17 +1094,18 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
log.fine(info); log.fine(info);
return false; // ignore return false; // ignore
} }
} }*/
setWFState (StateEngine.STATE_Running); setWFState (StateEngine.STATE_Running);
setAD_User_ID(AD_User_ID); setAD_User_ID(AD_User_ID);
boolean ok = setVariable (value, displayType, textMsg); Trx trx = ( get_TrxName() != null ) ? Trx.get(get_TrxName(), false) : null;
boolean ok = setVariable (value, displayType, textMsg, trx);
if (!ok) if (!ok)
return false; return false;
String newState = StateEngine.STATE_Completed; String newState = StateEngine.STATE_Completed;
// Approval // Approval
if (getNode().isUserApproval() && getPO() instanceof DocAction) if (getNode().isUserApproval() && getPO(trx) instanceof DocAction)
{ {
DocAction doc = (DocAction)m_po; DocAction doc = (DocAction)m_po;
try try
@ -1156,16 +1174,23 @@ public class MWFActivity extends X_AD_WF_Activity implements Runnable
|| MUser.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType)) { || MUser.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType)) {
MClient client = MClient.get(getCtx(), doc.getAD_Client_ID()); MClient client = MClient.get(getCtx(), doc.getAD_Client_ID());
client.sendEMail(doc.getDoc_User_ID(), Msg.getMsg(getCtx(), "NotApproved") client.sendEMail(doc.getDoc_User_ID(), Msg.getMsg(getCtx(), "NotApproved")
+ ": " + doc.getDocumentNo(), doc.getSummary() + "\n" + ": " + doc.getDocumentNo(),
+ doc.getProcessMsg() + "\n" + getTextMsg(), null); (doc.getSummary() != null ? doc.getSummary() + "\n" : "" )
+ (doc.getProcessMsg() != null ? doc.getProcessMsg() + "\n" : "")
+ (getTextMsg() != null ? getTextMsg() : ""), null);
} }
// Send Note // Send Note
if (MUser.NOTIFICATIONTYPE_Notice.equals(NotificationType) if (MUser.NOTIFICATIONTYPE_Notice.equals(NotificationType)
|| MUser.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType)) { || MUser.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType)) {
MNote note = new MNote(getCtx(), "NotApproved", doc.getDoc_User_ID(), null); MNote note = new MNote(getCtx(), "NotApproved", doc.getDoc_User_ID(), null);
note.setTextMsg(doc.getSummary() + "\n" + doc.getProcessMsg() + "\n" note.setTextMsg((doc.getSummary() != null ? doc.getSummary() + "\n" : "" )
+ getTextMsg()); + (doc.getProcessMsg() != null ? doc.getProcessMsg() + "\n" : "")
+ (getTextMsg() != null ? getTextMsg() : ""));
// 2007-06-08, matthiasO.
// Add record information to the note, so that the user receiving the
// note can jump to the doc easily
note.setRecord(m_po.get_Table_ID(), m_po.get_ID());
note.save(); note.save();
} }
} }

View File

@ -141,11 +141,13 @@ public class MWFResponsible extends X_AD_WF_Responsible
return false; return false;
} }
// User not used // User not used
if (!RESPONSIBLETYPE_Human.equals(getResponsibleType()) && getAD_User_ID() == 0) if (!RESPONSIBLETYPE_Human.equals(getResponsibleType()) && getAD_User_ID() > 0)
setAD_User_ID(0); setAD_User_ID(0);
// Role not used // Role not used
if (!RESPONSIBLETYPE_Role.equals(getResponsibleType()) && getAD_Role_ID() == 0) if (!RESPONSIBLETYPE_Role.equals(getResponsibleType()) && getAD_Role_ID() > 0)
setAD_Role_ID(0); setAD_Role_ID(0);
return true; return true;
} // beforeSave } // beforeSave

View File

@ -77,6 +77,10 @@ public class WFActivityManage extends SvrProcess
String msg = user.getName() + ": Abort"; String msg = user.getName() + ": Abort";
activity.setTextMsg(msg); activity.setTextMsg(msg);
activity.setAD_User_ID(getAD_User_ID()); activity.setAD_User_ID(getAD_User_ID());
// 2007-06-14, matthiasO.
// Set the 'processed'-flag when an activity is aborted; not setting this flag
// will leave the activity in an "unmanagable" state
activity.setProcessed(true);
activity.setWFState(StateEngine.STATE_Aborted); activity.setWFState(StateEngine.STATE_Aborted);
return msg; return msg;
} }