Erick's Blog
  • Home
  • Blog
  • Apps
    • Mortgage Calculator
  • PowerShell
    • Blog & Examples
    • Excel Reference
  • Windchill
    • Document Exporter
    • Document Worker
    • E.P.L.E.S.
    • Export Released
    • Property Checker
    • Windchill Business Analytics >
      • Part 01 - Program Logic
      • Part 02 - Getting Data with SQL Queries
      • Part 03 - Automating SQL Queries
      • Part 04 - Converting SQL Results to XML
      • Part 05 - Data Processing and Manipulation
      • Part 06 - Displaying XML in HTML
      • Part 07 - Auto Updating Displayed Data
      • Part 08 - Hosting Webpage with an Existing Apache Installation
      • Part 09 - Running Multiple Queries In Sequence
      • Part 10 - Calculating Data Trends
      • Part 11 - Making It Modular
    • Windchill Quick View
  • Reviews
  • Music
  • Contact

Windchill 11.0 Workflows - Part 2: Writing Your First Workflow Code

7/23/2017

4 Comments

 
Picture
The drag and drop interface is really useful for visualizing your workflows but you can't do everything without writing some code.  In Part 2, we are tasked with modifying the OOTB Promotion Request Approval Process workflow to require approvals based on the file types attached to the Promotion Request.
Requirements:
The workflow modifications we are going to make have two basic requirements.
  1. We want Promotion Requests to start certain activities only if there are certain object types on the request. i.e. If a Promotion Request has a WTPart and a Document, then we want there to be one activity for the WTPart and one for the Document which have different required users.
  2. OOTB, the workflow waits for all users to cast their vote before the workflow continues.  This can lead to delays in your work.  For example, say you have 3 people as approvers and your workflow requires all to approve for the items to move forward.  What if the first person who votes rejects the approval?  Right now, the workflow will wait for all others to vote even though it will obviously not be approved.  This is a gross waste of time and is something that we are going to fix.  In summary, we are go to make each activity that requires all to approve automatically go forward with a rejection based on the first reject vote.

Initial Setup:
If you haven't already saved a copy of the Promotion Request Approval Process workflow from Part 1, go ahead and do so.  We don't want to interfere with the OOTB workflow until we know our code works correctly.  Make sure to give it a relevant name and check it out.

Initial Thoughts:
Let's think about requirement 1 for a minute.  There are two ways we can go about doing this.
  1. Have the activities run in parallel.
  2. Have the activities run in sequence.
If I were to take a guess, I bet that running these activities in sequence may be more beneficial than running them in parallel especially because we are talking about different object types.  Maybe you are promoting an assembly which has a manual that contains a diagram of the assembly.  If the assembly gets rejected, then there will obviously be some changes or at least further discussions before it can be approved in the future.  Why would you want your document control team to approve the manuals if the assembly is not ready yet?  Starting with the three major object types, we are going to go this route in order of approvals:  CAD -> WTParts -> Documents.

Potential Issues:
Like most solutions, each one comes with its own set of issues.  It is impossible to get it perfect the first time and hard to get it perfect in any reasonable amount of time.  You are limited by what the software allows you to do, your thinking skills, and the information given to you in the form of requirements.  Thinking ahead about how the users will interact with the workflow and what they will do right and wrong is important in order to mitigate problems with your workflows.  I always try to get a proof of concept working to make sure what is needed is possible before I start to think about all the ways a user can mess up.  If there are ways to avoid problems by either writing more code or making instructions more clear, then you should consider spending the time to make the changes.  Workflows will not save you time if they are too complicated or too difficult for the users to understand.  Consider making a Visio diagram of your final workflow with brief descriptions of each step to hand out to users so they can see what needs to happen in order for their files to be approved.

Create the Workflow Layout:
We will start by first making the layout of our changes via the drag and drop editor that you have become familiar with in Part 1.  You are basically doing the same thing you did there but lets make some slight changes to each activity.
  1. Assigned activity name: CAD Approval
    1. Vote requirements: all, reject on 1st reject
    2. Approvers role: Design Engineer
  2. Assigned activity name: WTPart Approval
    1. Vote requirements: only 1
    2. Approvers role: Manufacturing Engineer
  3. Assigned activity name: Document Approval
    1. Vote requirements: at least 2
    2. Approvers role: Quality Engineer
Picture
Initial Workflow Layout Changes
All the assigned activities are linked together such that the next one only kicks off if any required previous ones were approved.  Hold on though, what happens if a user makes a promotion request that contains only a WTPart and Document?  According to this layout, it will still go through the CAD Approval activity first.  That's because we haven't added any logic yet to check which activities should be activated.  There are two ways to think about this part of the workflow.
  1. Do you want to workflow to continue if it doesn't have one of each object type on it?
  2. If you want the workflow to work regardless of how many unique object types are on it, what is the bare minimum requirement? i.e. Need a CAD and Document?  Need only 1 of any?
I am going to go with the second choice and allow the workflow to continue with any number of unique object types attached.

Psuedo Code:
If you are just starting out or if you like to make notes of your thinking process, I recommend writing psuedo code.  This is just a mix of human understandable words and basic code syntax which allows you to visualize what your code needs to do.  You should not feel embarrassed doing this.  It is much more important being able to understand what needs to be done than to know the code that does each part.  If I were to make psuedo code for out sequence of events it would look something like this maybe in a diagram form.
  1. Promotion Request has objects attached to it.
  2. Get a list of all the objects.
  3. For each object, check the object type.
  4. Create list of unique object types.
  5. Check list to see if certain object type exists.
  6. Only start activity if object type exists.

Expression Robot:
Now that we have our psuedo code, we need to figure out where to put our actual code.  You have probably noticed than many robots have tabs where you can type code.  There are many ways to do this but in order to keep things easy to understand, we are going to use an expression robot that starts before the activities.  Something like this:
Picture
Get Object Types Expression Robot Added
Get used to giving all blocks relevant names.  This is a simple procedure that makes updating and troubleshooting your work easier especially when you start to have more than one expression robot.

Your First Workflow Code:
Now this part is going to be a little bit more difficult.  A lot of learning this stuff involves seeing working code and how it is used.  You should download a copy of the Windchill Java Docs so you have the code reference for possible things you can do.  This is the actual Windchill API you will be working with.  There isn't any autocomplete or suggestions when writing code in the workflows.  All you have is a syntax check which will do 2 things:
  1. Make sure your Java syntax is correct i.e. not missing a ";".
  2. Check for valid downcasting and upcasting of Windchill types.
Your code could pass these checks and still not work properly or at all.  This will be a heavy trial and error process so be prepared to spend some time and make sure to have the monitor space to have all windows you need open.  Here is a list of windows you should have open:
  1. Web browser logged in as site admin to make workflow changes.
  2. Web browser logged in as organization admin/product manager to test workflow changes.
  3. We browser with the Windchill Java Docs open.
  4. Windchill logs folder to look at background method server logs for workflow code errors.
Although I don't have a good way to teach you the thinking process involved in doing this, I can share with you the code that does what we need to do and explain each line for you.  You can then repurpose this for future work.
Get Object Types Expression Robot Code

    

Workflow Variables:
You may have noticed that there are some local variables defined in the above code as well and one called "typeRoute" which doesn't appear to be declared anywhere.  What is this?  This is a workflow variable.  A workflow variable is a variable that can be read and set in any block.

Why do we need to use these?  You need to start thinking of workflow blocks as private code.  Anything that goes on in one block is not viewable by another.  What this means is that in order for block A to communicate with block B, we need to have block A set the value of a workflow variable and have block B read the value from that same variable.  We cannot pass local block variables between blocks.

Where are these defined?  On the main workflow editor page, there is a properties link in the top toolbar.  From there you have a variables tab that lists all of the workflow variables in the workflow plus options to create new or update existing ones.  You are limited to the types of variables you can create here.  If I could choose any variable type that Java has to offer, then I would choose to make typeRoute a list.  Since that option is not available, we are going to have to go to old csv route so we will make typeRoute a string.  Make sure to set the variable to allow for read and write access.  I just set it to full control to make things easy.

Tip:
Wherever you can type code in a block, there is usually a drop down list called "Insert" that shows all of workflow variables you have to work with.

Outputting Information to the Logs:
You can see that I have included a lot of "System.out.println" lines.  I do this because it makes things much easier to debug later on.  If you want to output variable values or any other information to the logs, add these lines.  A sample of the log output is below.
Picture
Background Method Server Log with User Defined Output

Activating Appropriate Activity Types:
We have our code but what is it actually doing?  It is creating a csv list in the string variable typeRoute of unique object types.  What it is not doing is telling the activities when to run or not.  We need a few more blocks to read the typeRoute variable and determine whether the activity should be ran.  I will do this with Conditional blocks using the below code.
Picture
Conditional Block Code to Determine if Activity Should be Ran
A few things to mention about the above.
  • The variable "result" is a variable that is reserved for the purposes of which output action arrow line to follow.  You can use a for each loop all you want to try and set this variable to multiple values in one block but the only value that will end up doing anything will be whatever is last.  As hinted by the code above, this means that you need to make conditional blocks for each object type you are checking.  You cannot do it in one block.
  • ​Routing events determine what the possible routing options are when result is set to one of them.  Make sure that result is never set to a value that is not included in the routing events.
Picture
Workflow with Conditionals to Start Activities Based on Object Type(s)
I have the code to just check the parent type.  We are currently grabbing the information for sub types as well.  How would you go about further filtering based on subtype?  If I have a document where there are 2 possible subtypes, I would:
  1. Use the first document conditional to check it any documents exists on the promotion request.
  2. Attach additional conditionals (1 for each subtype), to check for those and route accordingly.
​I am not going to show you this as it is purely simple logic at this point but try it out for yourself and see if you can make it work.

Optimization:
What we have done with all this code so far only really affects the approval route.  I just had you follow the original path for Reject and Rework.  What if you had a promotion request with a CAD document and a document and you selected rework?  According to our code, the rework route would take the workflow back to before the CAD document was approved which means that after the creator gives more information and completes the rework task, the CAD approver will get another task for the same object.  You have two options here:
  1. Use a workflow variable to determine if CAD approval has already been completed and skip the CAD approval next time.
  2. Copy and paste the entire rework loop such that the end of the loop goes straight to the conditional that activates the task where you left off.
I will leave this as homework for you to try out but it is important to always follow every route in your workflow and see if you can optimize paths.

Rejecting the Activity on First Reject Vote:
The last part of the code we need to implement is the rejection code.  We want the CAD approval activity to go to the rejection route immediately when the first reject vote comes in.  This ensures we aren't waiting for everyone else to vote when we already know the the results.  Go to the CAD approval activity -> Transitions tab.

This section allows you to run code depending on what has happened to the overall activity.  We want to use the Complete Task transition because we want to check for reject votes after each task is completed rather than when the entire activity is completed like it is doing now.
Picture
Reject on First Reject Vote
Test it out by adding two people to the design engineers role and reject with one.  The promotion request should then be rejected and the task on the other approver's list should now be gone.

Extra Credit:
  • What if you wanted to do this for rework as well?  Try modifying the code to reject and rework on the first of such votes.
  • What if you did want all activities to run in parallel?  I've attached an image of such below to show you how it would be done.  Try to understand the differences.
Picture
Running Required Tasks in Parallel

What's Next:
That's all for Part 2.  You can see that it is not too difficult to make meaningful changes once you have some sample code to work off of.  In Part 3, we will start using workflows to interact with the server.  This is something the you can't do in the drag and drop editor.  Stay tuned to see how much further you can take your workflows!
4 Comments
Philipp
8/21/2017 06:19:52 am

Dear Erick,

thanks for your detailed description on editing an workflow in Windchill. My Company is in the launichingprocess of Windchill and my boss assigend me the task to get in to the whole workflow subjekt.

And I find your blog :D

After reading your Workflow part 1 and 2 twice, I got have the question where you finde all the packages from Windchill ? Evertime you get data from Windchill you call Windchillpackages, is there a table of all usuable packages ?

Next step for me before we get access to windchill will be to refresh my java skills. Have you any more advices for me?

I´m looking forwared to here from you, sorry for my bad englisch.

Yours sincerely Philipp

Reply
Siddharth
7/4/2019 09:56:40 am

Hi Phillip,

Windchill API , You can find in Java Docs

Regards,
Siddharth

Reply
kannagi
4/10/2021 04:10:36 am

Hi Erick
Your blog is very informative. I am using windchill 11 and doing workflow customization to some extend. I want to know how to set the lifecycle state of targeted objects (EPMDocuments and WTParts) from within workflow to the state I prefer, which is different from target lifecycle state. I have to do it on some target objects on a particular condition. Please help me.

Reply
Rajnandini Yadav
6/2/2021 11:41:42 am

Your blog is very informative

Reply



Leave a Reply.

    Author

    PLM engineer while "on the clock", programmer, designer, dreamer all other times.

    Archives

    July 2017
    May 2017
    February 2017
    January 2017
    December 2016
    August 2016
    July 2016
    June 2016
    May 2016
    April 2016
    March 2016

    Categories

    All
    ASP.NET
    Batch Script
    C#
    Career
    Computers
    Creo
    Creo API
    Flash
    GameMaker
    GitHub
    Home Loan
    How To
    HTML5
    Java
    JavaScript
    MAME
    Mortgage
    Music
    .NET Core
    Office
    PC Games
    PfSense
    PowerShell
    Reviews
    Robot
    SQL
    Video Games
    Web App
    Windchill
    Windchill API

    RSS Feed

Copyright © 2018 Erick Johnson
  • Home
  • Blog
  • Apps
    • Mortgage Calculator
  • PowerShell
    • Blog & Examples
    • Excel Reference
  • Windchill
    • Document Exporter
    • Document Worker
    • E.P.L.E.S.
    • Export Released
    • Property Checker
    • Windchill Business Analytics >
      • Part 01 - Program Logic
      • Part 02 - Getting Data with SQL Queries
      • Part 03 - Automating SQL Queries
      • Part 04 - Converting SQL Results to XML
      • Part 05 - Data Processing and Manipulation
      • Part 06 - Displaying XML in HTML
      • Part 07 - Auto Updating Displayed Data
      • Part 08 - Hosting Webpage with an Existing Apache Installation
      • Part 09 - Running Multiple Queries In Sequence
      • Part 10 - Calculating Data Trends
      • Part 11 - Making It Modular
    • Windchill Quick View
  • Reviews
  • Music
  • Contact