Sunday 26 May 2013

Programmatically vote for a workflow

While workflow voting in Innovator is pretty simple there are times when you might need to vote via a method to get your desired level of automation.

I did this recently for two different clients with two very different needs.

One had some Item that we needed to "park" for a while with no-one being really responsible for them and then via a scheduled server method vote them back into active management and the other  wanted a very clean way of recording receipt of some returned goods and at the same time voting for the advancement of the workflow.

What follows is a sample server method (c#) for achieving the vote:

// Programmatic voting for an activity to facilitate some// additional automation
// called as a generic method.
// Limitations: This method expects that there is only one
// assignee for the vote.
// Passed in is the id of the Item that we need to vote for:
// expecting: <itemId>id</itemId>
// <itemType>type</itemType>
// <votingPath>path</votingPath>

Innovator inn = this.getInnovator();
string itemID = this.getProperty("itemId","");
string itemType = this.getProperty("itemType","");
string votePath = this.getProperty("votingPath","");
if ( itemID == "" ){
    return inn.newError("No Item ID supplied");
}
if ( itemType == ""){
    return inn.newError("No Item type supplied"); 
}
if ( votePath == "" ){
   return inn.newError("No voting path supplied"); 
}
// retrieve the "Active" workflow activity:
Item wfcItem = inn.newItem(itemType,"get"); // work flow controlled Item wfcItem
wfcItem.setID(itemID);
Item workflow = inn.newItem("Workflow","get");
Item workflowProcess = inn.newItem("Workflow Process","get");
Item wfpa = inn.newItem("Workflow Process Activity","get");
Item activity = inn.newItem("Activity","get");
activity.setProperty("state","Active");
Item activityAssign = inn.newItem("Activity Assignment","get");
Item wpp = inn.newItem("Workflow Process Path","get");
wpp.setProperty("name",votePath);
activity.addRelationship(activityAssign);
activity.addRelationship(wpp);
wfpa.setRelatedItem(activity);
workflowProcess.addRelationship(wfpa);
workflow.setRelatedItem(workflowProcess);
wfcItem.addRelationship(workflow);
wfcItem = wfcItem.apply();

if ( wfcItem.isError() ){
    return inn.newError("Error retrieving Workflow Process Item: " + wfcItem.getErrorString()); 
}
Item wfPaths = wfcItem.getItemsByXPath("//Item[@type='Workflow Process Path']");
if ( wfPaths.getItemCount() != 1 ){
    return inn.newError("Unable to get voting path: " + votePath);
}
string submitPathId = wfPaths.getItemByIndex(0).getID();

Item act = wfcItem.getItemsByXPath("//Item[@type='Workflow Process Activity']/related_id/Item[@type='Activity']");
if ( act.getItemCount() != 1 ){
    return inn.newError("Unable to get activity"); 
}
string actId = act.getID();
string vote = votePath;
string comment = "";
string assignId = "";
Item actAss = wfcItem.getItemsByXPath("//Item[@type='Activity Assignment']");
if ( actAss.getItemCount() != 1){
    return inn.newError("Unable to get activity assignment"); 
}
assignId = actAss.getID();
// Build the voting request
StringBuilder voteXml = new StringBuilder("");
voteXml.Append("<Item type=\"Activity\" action=\"EvaluateActivity\">");
voteXml.Append(" <Activity>{0}</Activity>");
voteXml.Append(" <ActivityAssignment>{1}</ActivityAssignment>");
voteXml.Append(" <Paths>");
voteXml.Append(" <Path id=\"{2}\">{3}</Path>");
voteXml.Append(" </Paths>");
voteXml.Append(" <DelegateTo>0</DelegateTo>");
voteXml.Append(" <Tasks />");
voteXml.Append(" <Variables />");
voteXml.Append(" <Authentication mode=\"\" />");
voteXml.Append(" <Comments>{4}</Comments>");
voteXml.Append(" <Complete>1</Complete>");
voteXml.Append("</Item>");

// Submit the vote
Item res = inn.newItem();
res.loadAML(String.Format(voteXml.ToString(),actId,assignId,submitPathId,vote,comment));
res = res.apply();

return res;


This method is called from a client method:

// vote for the RMA to move down the "Receive" path
var body = "<itemId>" + myItem.getID() + "</itemId><itemType>MyItemType</itemType>votingPath>MyPath</votingPath>";
var voteRes = inn.applyMethod("FT Programmatic Vote", body);
if (voteRes.isError()) {
    alert("Error voting for activity: " + myItem.getProperty("item_number") + ": " + voteRes.getErrorString());
}


3 comments:

  1. Hey Brian,

    Is it possible to get the value of a "vote" (Accept/Reject) when going through the workflow?

    ReplyDelete
  2. Brian,

    After promoting activity programatically, item is getting promoted to new LC state with new permission.

    In this permission, a user doesn't have rights to view this item and if it is given as a reference on any other Item as an ITEM property, it shows as Restricted.

    But, foreign properties of the same Item are not restricted and shows the data.

    Could you please suggest, how to hide this data??

    ReplyDelete
  3. Brian,

    I have posted a query on the automatic activity completion on ARAS community.

    http://www.aras.com/Community/forums/p/745/15718.aspx#15718

    With reference to the same I am asking you this question.

    Is there a way to activate more than one activity using EvaluateActivity.????

    E.g.

    Auto complete activity is Rework (Completing using Code)
    Rework has 2 paths which goes to parallel activities.
    tag in the code which you have provided works for one path only.
    Between tag if we pass more than one , it works for any 1 of them only.
    Is there a way that we can activate 2 activities using method??

    Thanks in advance

    ReplyDelete