In the category of Tips & Tricks…
Most BPM programmers simply create the BPM, enable, and run (pun intended)… Even I have been guilty. If it had documentation, it is sparse… and Version control? ha…
BUT LATELY, I have started adding version control & Comments directly into a BPM C# widget that is reserved for this purpose. (no code allowed per my rules). It is a detached widget (exception… see below).
When CHANGING or CREATING a BPM I do the following:
create a C# Widget to hold the purpose and versioning information… update the version in the header of the widget. Make the Corner color of this widget ORANGE (to highlight it).
document the purpose inside the widget with history.
Hmm… well, because I chose C# BECAUSE the first BPM I did this in was a Standard Data BPM and they don’t have Message Widgets…
That said… a message Widget would work fine.
Cloud customers probably dont have C# widgets (which I neglected to mention in my OP.)… This was already highlighted internally at Epicor when I posted something similar. But for those that DO have the C# widget, this can be huge.
Tim,
Great topic, just to add, not sure what everyone else is doing, but I export the object (whatever it is) and put the resultant file into bitbucket. It’s time consuming, but not as time consuming having to rebuild something from scratch.
Epicor please enable customization on the Method Directive and Data Directive maintenance, so we can spend some time applying our own version control hooks.
At minimum, can Epicor add the date of last save, as shown under the Dashboard module? When we search for the last modified dashboard I can sort by date… (I am not always taking notes of the names I create ! )
Having that date, in the search of a BPM would ease a lot the searching process…may as well add a file version as well as in the dashboard!
So the info is there probably but not shown !
The advantage of the notes would be kind of keeping track of what was changed…at the BPM level…A bit like the notes window that appears when we save as a customization. That would be great! That window opening on a save will remind you to put notes if needed! cannot forget!
The idea of enabling and disabling the BPM before moving to a new environment and of having a custom code block at the beginning of each BPM got me thinking…couldn’t I do something similar to create a set of Feature Flags that will control whether a collection of related BPMs fire or not?
Here’s what I came up with…
Create a UDCodeTypeID (I used "FeatureFlg").
Populate the FeatureFlg CodeType with a list of CodeID's related to your features. Use the "Active" checkbox to indicate whether the featured should be enabled or disabled.
In any BPM related to the feature, create a Boolean variable to hold the feature flag state (FeatureXEnabled).
Next, include a piece of code to check the status of the feature flag:
This will set the FeatureXEnabled variable to true only if the CodeID exists and is active. If the CodeID doesn't exist (you've just moved this feature to a new environment, for example), or if it is disabled, the FeatureXEnabled variable will be false.
Add a Condition block to your BPM to check the FeatureXEnabled variable. If true, proceed with your BPM, if false, stop.
This would effectively allow you to move BPMs to your production environment, but prevent them from running until you are ready to turn on the feature. And you don’t have to go in and find all of the related BPMs and check the “enabled” flag on each one to do it.
Not sure if anyone will find this useful, but I figured I’d share just in case.
Love this idea Doug! I can see even doing a “limited” release by adding a Security Group in the mix so some users get a new version of code to test while others get the older code. Great idea.
there is no need to actually return a record. We only need to know if the system found “any” active… The Any command returns a very quick “true/false” result. The query you did will return the entire record instead of just the field(s) you need.
I also added Company to the lookup so the entire key is populated.
Note, if you really needed to have the record and more values, you should put a “Select” to choose the fields. the example below returns two fields only. This is a common mistake where people return entire dataset when they only wanted one/more values.
I appreciate the tip. I didn’t know about the .Any() method. That’s definitely a great thing to add to my arsenal! And you make a good point in adding the company, too!
I do have to admit that, although I am familiar with the .Select() method, I don’t use it nearly as often as I should. That’s something I am going to have to start using more often to make my code more efficient.
Doug, don’t feel bad. I just really learned about .Any recently. I have known about the .Select for quite a while, and always try to use it. Recently, I found I had a query on a rather large table that I was returning 9 columns, which makes the query LOOK bigger, but it is still faster than returning everything (the lazy way).