WISCONSIN EUG OCT 2016 MTG - BPM Presentation Code Examples

All,

For those of you who attended the October meeting in Delafield WI, here are a few of the code examples that Josh and I talked about in the technical breakout session.

Actions_Read Me.txt (1017 Bytes)
PostTran.ActionsExample.cs (11.4 KB)
BPM Email Example_Read Me.txt (394 Bytes)
GetDtlPOLineInfo.Post.EmailExample.cs (11.2 KB)
WCF Bindings_External Applications.txt (2.0 KB)
WebConfig_Dev.txt (836 Bytes)

the following links will get you project templates for VS for working with BPM’s and UI customizations

Happy coding, and feel free to like this post so i know you found this useful!

Thank you,

Rob

15 Likes

+1 many thanks

Oh nice, code review one night this week for me. I’ll be curious what you came up with :slight_smile:

i need to keep learning so don’t hold back any punches lol

thanks, this may help!

I’ll gladly punch you :smile:

1 Like

Jose, If I shared my code you wouldn’t just throw punches, you’d go full MMA.

1 Like

I have attached the data validation classes I use accross Epicor as an External DLL. It includes the HTML email templater demonstrated. I still need to work on the Visual Studio plugin so that it works with 10.1 but hopefully I can do something with that in the public form in the future. BPMs from BO push back into Epicor from Visual Studio but I have to fix DT and multi company. The auto pulling in of the CS filles and reference discovery works again.

WCI.Data.dll (10 KB)

Above comprised of below.

FormatExpression.cs (2.4 KB)
TemplateFormater.cs (4.3 KB)
Validation.cs (2.3 KB)

2 Likes

@rbucek what sort of cool things could one do with VSTO plugin? I know the list could be limitless, but what are some useful/practical things we could gain? One thing I can think of is emulating the EPICOR module that allows you to add records to DB through email - which sounds pretty sweet!

I built our own version of crm right into outlook. Works nicely, been done a couple different ways.

Joshua Giese
CTO
920.437.6400 x342
Wisconsin Converting Inc.

1 Like

It’s usually very business specific. Ours was driven by customer requirements. We have to have material traceability back to the steel mills and we get material test reports as pdf’s via email from our suppliers. We need to recall those by job, by assembly when we send out new products to our customers. Tracing these and recalling them from a file cabinet was a nightmare. So I built the pluggin to recognize when it got an email with an attachment of that type. It looked up the supplier by email in the supplier maintenance area of epicor, brought back relevant data, filled in fields on the custom outlook form that was only visible in emails that contained MTR attachments, it gathered other info from the subject line and body, automatically saved the attachment in our file server and created an index record in a UD table in Epicor. It was simple to write a dashboard at that point that prompted a job number and voila, a list of all MTR’S that they could print from within Epicor along with the assembly traceability. We took a task that required almost 20 man hours a week to manage into something that took an hour or two.

1 Like

Damn Rob, is that ALL it did? Lol, very impressive

Josh’s CRM thing is way cooler.

I could spend some serious time in here :wink:

I’ll throw some guidelines I give to internal devs on GetDtlPOLineInfo.Post.EmailExample.cs. Some items are religious style so take those with a grain of salt. Other comments are from scars of picking up others code (I love the old saying - Always write your code like the person taking over is a serial killer with your address)

First reading the code is kind of difficult to pickup on areas due to the verbose nature. Putting in
‘foo.X == false’ is the same as !foo.X. Same goes for bar.Y==true. That’s just a bar.Y statement. It’s a true or false value already so no need to make the code longer and harder to read.

Along that same line there are some complex action statements - a couple repeated I think:
<…>
&& this.ttJobHead.Any(
r1 =>
r1.SysRowID == r.SysRowID
&& r1.Unchanged()
&& r1.JobReleased != (r.JobReleased)
&& r1.JobReleased == (false)));
what the heck is that comparison you are doing? Will someone know 6 months from now (or yourself next week?)
Refactor that out into its own method and reuse it. Especially when you are doing the same comparison in a couple of areas. If you change the logic at some point you may only fix one, not two. If you pull that out into a common method you prevent breaking things in the future. Furthermore you can name the method something explanatory and avoid the need to put in comments as you name the method what it does - self documenting.

Another positive in pulling out things into a common method is the ability to create Unit Tests to verify functionality. That way when you come back and fix things in 6 months, you run the tests and realize you just broke things - avoiding those long weekends when you mess up a deployment :wink:
That is also the reason to remove the goto statements and make those if then queries instead against refactored out methods Then those methods can again be unit tested…

1 Like

Another item that makes things difficult to follow is the numerous parameters passed around:
<…>
Action<string, string, string, string, string, string, string, string, decimal, decimal, decimal, decimal, decimal, DateTime> InsertUDRecord
= (workOrder, action, type, jobNum, partNum, material, rev, opCode, asmbl, qty, rqdQty, oprSeq, mtlSeq, startdate)
<…>

Instead of passing these long lists of variables around, create a new class named appropriately to describe this structure and populate an instance, pass that around, etc. If you need to add a field then you change less code as well.

1 Like

WARNING - Memory ‘Leak’

     var UD32svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.UD32SvcContract>(Db);

This create an instance of the BO you want to call. That BO create a db connection. When you are done with the BO you should dispose it as soon as possible. If you don’t, it sits around until the end of the server call where the framework walks through all the BOs and libs laying around and cleaning them up. In most cases this might not be a bad but in the case of a report or process or long bo method this may suck up all available db connections until the dotNet garbage collector comes along in the background to clean things up. Think MRP or Posting Engine and those calls can take some time starving the app server from accessing the db.

Instead, wrap the stand up of BOs and Libs in using statements:

using (var UD32svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.UD32SvcContract>(Db))
{
<…>

This gives back the db connection and frees memory asap.

1 Like

WCF Bindings helper…

Take a look at the ImplFactory in Epicor.ServiceModel.dll. / Epicor.ServiceModel.Channels.ImplFactory.CreateImpl()

This has several overloads to create client proxies easily with most of the differing parameters of interest. It’s used by Task Agent, all Client BOs, Social, Search, …

GetCustomBinding() also will help with setting up all the various binding types ‘in the can’ for E10 -

Epicor.ServiceModel.Bindings.BindingName has constants for all those bindings.

NOTE - These have evolved over the releases so have more overloads from 10.0 to 10.1.400 to 10.1.500, etc.

@Bart_Elia lol that’s code Epicor stubs out from the condition element used in the BPM designer…so I don’t know? Not much i can do there. That being said, thank you so much, your feedback is great! Just what i needed to hear, lots of things to think about… the only code i wrote is in

so if you are working within a BPM and Epicor takes your custom code action, creates a method out of it, how do you refactor anything into it’s own method? I understand i could technically build a library, and make a bunch of classes with methods in it, reference that, but most of this is so specific, I’ll never ever use it anywhere else in the system? Just curious, I’m not a coder by background or trade, but i do enjoy doing it when the task requires it. There are a lot of variables being used in that action and it looks clunky yes, there’s that class question again, how to create that within the scope of the custom action code element, so much to learn lol, what are the limitations there and how to work within that?

Thanks again!

Ahhh! Sorry, like I mentioned before if you are doing code in BPM I personally - (Not a company endorsement here but a personal feeling) - I personally think that if you go into writing code it would benefit more from creating an external assembly for BPMs and calling out to it for all the normal reasons - version control, unit testing, stability, etc.

I did not really look at the business process you are working at to see if you ‘need’ code as opposed to the BPM designer widgets. We have been slowly increasing the UI widgets available in BPM to try to make that more of an actionable designer and fit more customer scenarios - less code.

Now I’ll have to go back and load up your sample to look again :wink:

Hey Bart
What is the reason for doing your own DLL? My concern with going with external DLL’s is the constant re-compiling. If you use any of Epicor’s DLL’s in your custom DLL then that is tied to whatever Epicor version X. When you guys release a patch every 2 weeks… or a service pack I’ll have to constantly re-compile my custom DLL to work with the new version of the Epicor DLL. Am I wrong? do you guys not increment the versions of the DLLs with patches / service packs?
I’ve run into this issue several times, but maybe there is something I am missing.
Just curious if there is a better way to handle that.