Product configuration ERP 10 where to start

First I like to think I try to learn before asking for help. Where can I find a best practices guide for product configuration?

Here is our situation. We have product configuration with so much C# they often take over 5 minutes to complete the configuration of what in my expierence is a fairly simple part. There are hidden fields with crazy string manipulation calls to dozens of UD methods that access the database via Entity. Thousands of lines of code and no GUI to help navigate between method calls or intellisense to help with code generation.

My quesiton is: Is this normal for product configuration? Our Epicor Consultnat (Epicor Employee) says yes although there are some potential improvements. I just can’t belive it takes all this custom code to get drop down boxes to filter or a messagebox to tell you that a length isn’t allowed. I guess i expected a more data driven approach to filtering and controling selections.

Just looking for a place to learn the right way and verification that all the above is normal.

Pete

Without specific examples I would generally agree with this. The configurator system is kind of clunky, and can be hard to keep organized and clear. Often times simple things do take more work than you would expect.

Do you mean it takes the user 5 minutes to fill out the data or it sits there processing for 5 minutes? I think my configurators are decently complex, or at least average, and I don’t have anything that takes that long. They certainly do not feel like a smooth modern application, but I think the longest wait for anything is under a minute…

I’ll echo @Evan_Purdy’s comments. We’ve got a 15 configurators and each has a number of string manipulations, field data checks, field visibility checks, UD methods, database calls, etc. and are reasonably complex in the logic, but all run fairly quick.

I will add that this is not an application that you are writing, but rather a chunk of code that effectively runs in a runtime-spawned processing ‘fork’ within the client app. (I’m not sure of the exact word at the moment, but container and virtual machine aren’t right either…) In addition, you are relying on the Epicor client to be your debugger and truthfully it is simply written for a subset of the overall C# capability set. It would’ve been nice to allow us to ‘fork’ out and use VSCode, or embed the VS IDE, or something to write and debug the configurator code - thus ensuring compatibility while enabling ALL of the cool features - but they have not done that yet. I suspect something quite new is in the works as the platform continues to evolve to a more web-oriented offering and honestly we are in a holding pattern until we hear what’s going on before we do any serious re-coding of our CFGs.

1 Like

My recommendation as a place to start is the Embedded education for Configurators. It’s pretty basic and may not be enough to help you out but I think it’s a good start. I would also agree with @MikeGross and @Evan_Purdy with the caveat that I have found that code that performs the same function can operate in substantially different amounts of time. I know I was redesigning a configurator and it ran a 15 second load time and then I was looking at another configurator I was working with and it loaded in about 2 seconds but they did almost the exact same thing so I copied the faster configurator and modified it where needed.

Personally I think 5 minutes per configuration is a little excessive. I personally strive to keep everything as streamlined as possible as any wait time that I introduce into the process is magnified substantially.

Here is an example of a single configurator. There are 132 methods associated with it.

Here are some of the inputs for the same configurator.

And here is a little section of code for just one of the 132 UD Methods associated with this configurator.

string Compliance = ((Inputs.Configuration_Cmb.Value == “STD” && (Inputs.Compliance_Cmb.Value == “BCBC” || Inputs.Compliance_Cmb.Value == “CSA” || Inputs.Compliance_Cmb.Value == “OBC” || Inputs.Compliance_Cmb.Value == “QBC”)) ? (“BLANK”) : (Inputs.Compliance_Cmb.Value));
string Length = ((Inputs.Configuration_Cmb.Value == “CST”) ? (“NONE”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value <= 30) ? (“30”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 30 && Inputs.Length01_Dec.Value <= 60) ? (“60”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 60 && Inputs.Length01_Dec.Value <= 90) ? (“90”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 90) ? (“120”) : (Inputs.Length_Cmb.Value))))));
decimal DecimalLength = ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE”) ? (System.Convert.ToDecimal(Length)) : (Inputs.Length01_Dec.Value));
string DecimalLengthMM = Inputs.Z_Length01MM_Lbl.Label;
string Depth = ((Inputs.Configuration_Cmb.Value == “CST”) ? (“NONE”) : ((Inputs.Configuration_Cmb.Value == “STD” && (Compliance == “” || Compliance == “BLANK” || Compliance == “NONE” || Compliance == “STD” || Compliance == “JUV”)) ? (“2050”) : ((Compliance == “OBC”) ? (“2075”) : ((Compliance == “CSA”) ? (“2100”) : ((Compliance == “BCBC”) ? (“2225”) : ((Compliance == “QBC”) ? (“2350”) : (Inputs.Depth_Cmb.Value)))))));
decimal DecimalDepth = ((Inputs.Configuration_Cmb.Value == “STD” && (Compliance == “” || Compliance == “BLANK” || Compliance == “NONE” || Compliance == “STD” || Compliance == “JUV”)) ? (20.5m) : ((Compliance == “OBC”) ? (20.75m) : ((Compliance == “CSA”) ? (21) : ((Compliance == “BCBC”) ? (22.25m) : ((Compliance == “QBC”) ? (23.5m) : (Inputs.Depth01_Dec.Value))))));
string DecimalDepthMM = Inputs.Z_Depth01MM_Lbl.Label;
string Object01 = Inputs.Object01_Cmb.Value;
string Object02 = Inputs.Object02_Cmb.Value;
string Object03 = Inputs.Object03_Cmb.Value;
string Object04 = Inputs.Object04_Cmb.Value;
string Object05 = Inputs.Object05_Cmb.Value;
string Object06 = Inputs.Object06_Cmb.Value;
string Object07 = Inputs.Object07_Cmb.Value;
string Bowl = ((Inputs.Configuration_Cmb.Value == “STD”) ? (“WB-TR1”) : (Inputs.Bowl_Cmb.Value));
string BowlQuantity = ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value <= 30) ? (“1”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 30 && Inputs.Length01_Dec.Value <= 60) ? (“2”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 60 && Inputs.Length01_Dec.Value <= 90) ? (“3”) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 90) ? (“4”) : (Inputs.BowlQuantity_Cmb.Value)))));
decimal DecimalBowlQuantity = ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value <= 30) ? (1) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 30 && Inputs.Length01_Dec.Value <= 60) ? (2) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 60 && Inputs.Length01_Dec.Value <= 90) ? (3) : ((Inputs.Configuration_Cmb.Value == “STD” && Inputs.Length_Cmb.Value == “NONE” && Inputs.Length01_Dec.Value > 90) ? (4) : (Inputs.Bowl_Dec.Value)))));
string DrainCap = ((Bowl == “NONE”) ? (“NONE”) : ((Bowl == “WB-TR1” && Inputs.DrainCap_Cmb.Value == “NONE”) ? (“BLANK”) : (Inputs.DrainCap_Cmb.Value)));
string BowlColor = ((Bowl == “NONE”) ? (“NONE”) : ((Bowl == “WB-TR1” && Inputs.BowlColor_Cmb.Value == “NONE”) ? (“BLANK”) : (Inputs.BowlColor_Cmb.Value)));
string ImageBowlColor = ((Bowl == “NONE”) ? (“NoImageFound”) : ((Bowl == “WB-TR1” && Inputs.BowlColor_Cmb.Value == “NONE”) ? (“NoImageFound”) : (Inputs.Z_BowlColor_Pic.Value)));

The reality is that this is unmanageable. We have 86 configurations. A single configuration can have over a hundred UD methods. Many of the UD Methods contain thousands of lines of code. With no debugger or tools to analyze performance.

My general rule is when I am tasked with building something, but I feel like to do so is just digging an even deeper hole, I need to make sure there is not a better way.

Thanks for the replies.

Peter

My initial guess on those is that there are individual methods per combo box to determine the drop down. You may find some immediate relief if inputs are being sent back and forth between server side methods and client side methods. Assuming they are server side methods and that the inputs are being sent which I believe is the default.

Also the code snip-it you gave looks like it is only defining inputs and not actually doing anything so it’s difficult to give advise on what should be done. There is clearly some meaning with the CBP_ prefix, and if it’s just setting the filters on a combo box there are significantly easier ways to do that if it’s doing significantly more than than that my theory is shot to crap.

-Max

1 Like