Community Tip - New to the community? Learn how to post a question and get help from PTC and industry experts! X
OOTB, the CR only waits on the Change Notice completion if the user acknowledges their creation of the change notice. Functionally, the process continues since the the change notice is created and the user can proceed one. I know its a training issue but the CR workflow is halted until the user completes a task and could impact resolution dates. Do others have this problem and how have you solved it?
Solved! Go to Solution.
You can also build your own email notification loop. We have these coming off each task now.
The task transition sets a variable that kills the loop the next time the timer goes off:
As far as modifying the out-of-the-box workflow, I can't imagine not having done that. We've improved so many things over the years, and I've never had to do anything to it after each upgrade, at least not yet...
If I understand correctly, the issue is the user who gets the Create New Change Notice task is holding up the game and needs to be nudged.
Have you tried making it very visible who’s holding up the game.
I have two approaches to do this.
One is a custom banner and the other is a custom data utility both add to the object’s info page if the object is on a CR (or CA, CN, Promotion Request or whatever).
In this case, if the object it linked to a CR the detail page displays a message stating the activity name, Create New Change Request, the user who the activity is assigned to and, wait for it, how long the activity has been on the users task list.
The code can be written such that the message does not display until the task is 2 days (or whatever) old.
It’s amazing how something like this gets everyone’s attention. 😂
Where is this guy when you need him?
"It looks like you have some tasks to complete"
Hi @d_graham and @avillanueva
this is a good idea to attract users attention that there is not completed task.
I would advice an another option. Do a small automation, if the Change notice is created and a task started (implementation state) complete the task Create New Change Notice in the change request workflow.
I can imagine there are many reason why do not automate it but it can be more user friendly 😄 if users usually just forget to complete task, the code can do it for them :D.
PetrH.
If you want to edit or copy the Change Request Workflow, you can set a deadline for the task and add reminder emails. Once the deadline has passed, the task on their Windchill home page will have their Deadline date value show up in a different color (I think it's red). Unfortunately, the max emails without additional customization appears to be 2. Per the help documentation: "Notify the responsible role—You can use these options to specify when the notification should be sent. If you do not specify a date in relation to the deadline, then the notification is sent when the deadline is reached."
The biggest downside to editing/copying a workflow is that whenever you upgrade Windchill you'll have to review if PTC made any changes to the OOTB workflow and manually incorporate the changes. You'll want to have good documentation about what you've customized.
HI @lhoogeveen
Good advice if the task should be done instantly by user after the task starts.
If responsible user has another work to complete it can takes a week then the task is completed.
There can be just two notification emails to remind the completion.
And I know many users ignore that emails.
PetrH.
One solution I have implemented is a loop in the workflow.
The loop includes a timer robot that goes to an email robot which send the reminder email.
Include a conditional robot after the Create New Change Notice robot that will terminate the timer robot.
So, the robot the has a connector to the Create New Change Notice also has a connector to timer robot.
Timer robot goes to email robot and email robot connects (loop link) back to timer robot.
Something like that.
David
You can also build your own email notification loop. We have these coming off each task now.
The task transition sets a variable that kills the loop the next time the timer goes off:
As far as modifying the out-of-the-box workflow, I can't imagine not having done that. We've improved so many things over the years, and I've never had to do anything to it after each upgrade, at least not yet...
Hi @TomU
I like the idea with timer. Good one.
The update/upgrade issues are jut connected with modification of OOTB workflows/lifecycles.
The system administrator has to work with this information.
I always advice to create own new workflow from existing one and also create own lifecycles that use my workflows.
This way you can avoid many issues with the update/upgrade issues. (load data always overwrites OOTB WF LC OIR)
PetrH
Yes, our system is the same. The lifecycle templates and workflows that we use have all been copied at the ORG level. We don't actually use any of the 'native' ones in production.
@TomU Great idea with the timer loop. We've copied the workflows at the ORG level as well to prevent our changes from getting overwritten and make it easy to compare with the latest OOTB workflows. Most of the time PTC doesn't change anything, but I did notice they recently added some steps for BOM Redlines in the OOTB Change Workflows. We haven't done anything with WTPart BOM Redlines yet, but we'll need to look at incorporating them if we ever do.
@TomU How are you building the Promotion Request {number} and {URL} variables? Having variables like that to reuse throughout the workflow would be handy.
I'm sure I just copied and pasted stuff from other community posts. I have no idea how to manually write most of this stuff.
Number (and change the PR name)
// get promotion request number
number = ((wt.maturity.PromotionNotice)primaryBusinessObject).getNumber().toString();
// change name of promotion request
wt.maturity.PromotionNotice pn = (wt.maturity.PromotionNotice) primaryBusinessObject;
wt.maturity.PromotionNoticeIdentity promotionNoticeIdentity = (wt.maturity.PromotionNoticeIdentity) pn.getIdentificationObject();
promotionNoticeIdentity.setName("Promotion Request " + number);
wt.fc.IdentityHelper.service.changeIdentity(pn, promotionNoticeIdentity);
URL
String activityName = "";
wt.fc.QueryResult qr=wt.workflow.status.WfWorkflowStatusHelper.service.getProcessComponents((wt.workflow.engine.WfProcess)self.getObject());
while (qr.hasMoreElements()) {
Object elem = qr.nextElement();
if (elem instanceof wt.workflow.work.WfAssignedActivity) {
wt.workflow.work.WfAssignedActivity activity =(wt.workflow.work.WfAssignedActivity)elem;
activityName = activity.getName().toString();
System.out.println("Activity Name: " + activityName);
// if(activity.getName().equalsIgnoreCase("TEST 1")){
java.util.Enumeration assignments = activity.getAssignments();
wt.workflow.work.WfAssignment assignment = null;
if( assignments.hasMoreElements()){
assignment = ( wt.workflow.work.WfAssignment ) assignments.nextElement();
if( assignment != null ){
wt.fc.QueryResult workitems = wt.fc.PersistenceHelper.manager.navigate( assignment, wt.workflow.work.WorkItemLink.WORK_ITEM_ROLE, wt.workflow.work.WorkItemLink.class );
if( workitems.hasMoreElements() ){
wt.workflow.work.WorkItem currentWorkItem = ( wt.workflow.work.WorkItem ) workitems.nextElement();
com.ptc.netmarkets.model.NmOid contentOid = new com.ptc.netmarkets.model.NmOid(com.ptc.netmarkets.work.NmWorkItem.TYPE, currentWorkItem.getPersistInfo().getObjectIdentifier());
com.ptc.netmarkets.util.beans.NmURLFactoryBean urlFactoryBean = new com.ptc.netmarkets.util.beans.NmURLFactoryBean ();
urlFactoryBean.setRequestURI ( com.ptc.netmarkets.util.misc.NetmarketURL.BASEURL );
URL = com.ptc.netmarkets.util.misc.NetmarketURL.buildURL ( urlFactoryBean, com.ptc.netmarkets.util.misc.NmAction.Type.OBJECT, com.ptc.netmarkets.util.misc.NmAction.Command.VIEW, contentOid, null);
// System.out.println("URL: " + URL);
}
}
}
}
}
URL = "<a href=\"" + URL + "\">" + activityName + "</a>";
// System.out.println("Final URL: " + URL);
I also build (and rebuild) a table listing all the promotion objects and then include this in the notification emails.
String style = "style=\"border: 1px solid; border-color:#808080; padding: 0.2em; padding-left: 0.8em; padding-right: 0.8em; font-family: arial; font-size: 0.8em; font-weight: bold; color: #ffffff \"";
String style1 = "style=\"border: 1px solid; border-color:#808080; padding: 0.2em; padding-left: 0.8em; padding-right: 0.8em; font-family: arial; font-size: 0.8em; color: #464646\"";
String style2 = "style=\"border: 1px solid; border-color:#808080; padding: 0.2em; padding-left: 0.8em; padding-right: 0.8em; font-family: arial; font-size: 0.8em; color: #464646; background-color: #f7f7f7 \"";
promotion_objects = "<table style=\"border: 1px solid; border-color:#808080; border-collapse: collapse\">\r\n";
promotion_objects = (promotion_objects + "<thead style=\"background-color: #4caf50\"><tr>\r\n");
promotion_objects = (promotion_objects + "<td " + style + ">Number</td><td " + style + ">Name</td><td " + style + ">Version</td>\r\n");
promotion_objects = (promotion_objects + "</tr></thead>\r\n");
promotion_objects = (promotion_objects + "<tbody>\r\n");
wt.fc.ReferenceFactory referenceFactory = new wt.fc.ReferenceFactory();
HashMap map = new HashMap(1);
wt.httpgw.URLFactory urlFactory = new wt.httpgw.URLFactory();
Integer i = 1;
wt.maturity.StandardMaturityService p = new wt.maturity.StandardMaturityService();
wt.maturity.PromotionNotice pn =(wt.maturity.PromotionNotice)primaryBusinessObject;
wt.fc.QueryResult pn_targets;
pn_targets = (wt.fc.QueryResult) p.getBaselineItems(pn);
wt.epm.EPMDocument epmDoc = new wt.epm.EPMDocument();
while (pn_targets.hasMoreElements())
{
Object obj =pn_targets.nextElement();
String objType =obj.getClass().getName();
if (objType.equals("wt.epm.EPMDocument"))
{
epmDoc = (wt.epm.EPMDocument)obj;
String epmNumber = epmDoc.getNumber().toString();
String epmName = epmDoc.getName();
String epmCADName = epmDoc.getCADName();
String epmVersion = epmDoc.getVersionIdentifier().getValue();
String epmIteration = epmDoc.getIterationIdentifier().getValue();
// String epmState = epmDoc.getState().toString();
// String epmState = epmDoc.getLifeCycleState().getDisplay();
map.put("oid", referenceFactory.getReferenceString(epmDoc));
String epmURL = urlFactory.getURL("app/#ptc1/tcomp/infoPage", map).toString();
promotion_objects = (promotion_objects + "<tr>\r\n");
if (i == 1) {
promotion_objects = (promotion_objects + "<td " + style1 + ">" + epmNumber + "</td>\r\n");
promotion_objects = (promotion_objects + "<td " + style1 + "><a href=\"" + epmURL + "\">" + epmCADName + "</a></td>\r\n");
promotion_objects = (promotion_objects + "<td " + style1 + ">" + epmVersion + "." + epmIteration + "</td>\r\n");
// promotion_objects = (promotion_objects + "<td " + style1 + ">" + epmState + "</td>\r\n");
i = 2;
} else {
promotion_objects = (promotion_objects + "<td " + style2 + ">" + epmNumber + "</td>\r\n");
promotion_objects = (promotion_objects + "<td " + style2 + "><a href=\"" + epmURL + "\">" + epmCADName + "</a></td>\r\n");
promotion_objects = (promotion_objects + "<td " + style2 + ">" + epmVersion + "." + epmIteration + "</td>\r\n");
// promotion_objects = (promotion_objects + "<td " + style2 + ">" + epmState + "</td>\r\n");
i = 1;
}
promotion_objects = (promotion_objects + "</tr>\r\n");
}
}
promotion_objects = (promotion_objects + "</tbody>\r\n");
promotion_objects = (promotion_objects + "</table>");
// System.out.println(promotion_objects);