MRP Suggestions for Unfirm Releases

this might be a common requirement, but it is not common knowledge that PartDtl is left in a state of disrepair when updating OrderRel with a BPM.

The way I have done this is to always modify both OrderRel and PartDtl at the same time with code if I am firming/unfirming the OrderRel record.
Below is some UNTESTED code that should show you how to sync up the OrderRel and PartDtl…

int orderNum = 12345; //testing value
bool firmFlag = true; //testing value
using(var txScope = IceContext.CreateDefaultTransactionScope()) {

	var dbOReleases = Db.OrderRel.With(LockHint.UpdLock).Where(o =>
		o.Company == CompanyID &&
		o.OrderNum == orderNum &&
		o.FirmRelease == firmFlag);

	foreach (var dbORel in dbOReleases) {
		dbORel.FirmRelease = firmFlag;

		var dbPartDetails = Db.PartDtl.With(LockHint.UpdLock).Where(p =>
			p.Company == CompanyID &&
			p.OrderNum == dbORel.OrderNum &&
			p.OrderLine == dbORel.OrderLine &&
			p.OrderRelNum == dbORel.OrderRelNum &&
			p.FirmRelease != dbORel.FirmRelease);

		foreach (var dbPartDtl in dbPartDetails) {
			dbPartDtl.FirmRelease = dbORel.FirmRelease;
		}
	}

	Db.Validate();
	txScope.Complete();
}
3 Likes

Thank you very much for the insight, Tim.

Sorry for the dense question; especially as it seems you already answered it; but are you saying that a BPM that update OrderRel’s firm status should always sync PartDtl?

@Alexandre_Pothier, @EDoe, are you aware of this?

Actually, this is a great question. This is true for a lot of Epicor. I learned early on that by setting a data field directly doesn’t always do what you think. There can be code behind these value changes that are updating other tables: JobHead.JobClosed, OrderDtl.LineOpen, etc. That is why Epicor highly prefers we work with the Business Objects and not directly with the database. Many of us are used to having that kind of Access (pun intended) in the past but in modern software architectures that use the Entity Framework (or other ORMs) take care of this stuff in the background. Manually changing fields does not.

4 Likes

Thanks, @Mark_Wonsil that’s very helpful, and I apologize @rosst if we’re at all getting off your original topic.

I’m finding it quite a challenge to find information on using the BOs, whereas info on the DB-level manipulation is obviously as common as dirt.

I’m not completely clear on where “working with the business objects” actually occurs. Does it mean simply calling a method in my code instead of setting a DB field to a given value - and if so, where can I learn more about that? Or does it mean only using widgets from the BPM builder as much as possible?

Thanks!

The BEST way to learn how to do these things is to watch what the Epicor client does and this is done through tracing. That’s what all the successful people on this list do. @josecgomez took it a step further and created a Trace Helper Utility that helps analyze trace files. If you mimic the client then the server can’t tell it’s not their own client. We can use BOs in REST, UBAQs, BPMs, Epicor Functions, and custom code.

2 Likes

Not a problem, @SteveFossey. I’m happy to help contribute the the general understanding of everyone.

The general recommendations I’ve seen are definitely to use BOs wherever possible. This would include in customizations, BPMs, and even external applications. Typically, it’s encouraged to reference the “Customization User Guide”, “ICE Tools User Guide”, and “Converted Code Programming Guide”. Each of them are useful in their own scenarios. Google and this forum are fantastic tools, as well.

The widgets are a huge help in BPMs and referencing the BOs through code differs between BPMs and customizations.

edit: A link I have bookmarked and have referred to numerous times for helpful examples of code usage: E10 Code Examples

2 Likes

Well… Epicor would recommend that you use Business Objects whenever possible, but I know (as an Epicor Employee) that there are many people who break this rule. When you do break the rule, you will have situations where you also break the data. Then it becomes your own responsibility to fix the data. If you make a BPM that updates the OrderRel, you need to make sure that it also updates any other fields.

1 Like

Agreed!

I have a feeling that what I’m asking must be very obvious to everyone but me, because so many people haven’t noticed / answered that part of my questions; but how do you “use the business object”!?

To take the above example specifically, if the non-canonical way is something like

OrderRel.FirmRelease = true;

in a piece of code; what is the corresponding business object way of accomplishing this? I have the guides referred to above, and I’ve looked through the code examples, but there must be some very obvious piece of the puzzle I’m missing!

OK, that’s very cool. Hopefully this will help me understand how to emulate what the application is doing, because right now that’s eluding me.Thanks very much.

Another tool you can use is the Business Logic Tester. You should be able to see it on your server under the Utilities folder. Once you set it up (use info in your Client/Config folder), you can open any Business Object and see all of the methods. You can also execute those methods right there as well. You’ll see the SalesOrder object has over 100 methods and a few of them will do what you want. Again, the hints are in the trace.

Keep at it!

One way to find out…

  1. go into an order
  2. go to the release, make sure it is NOT firm (save if necessary)
  3. TURN ON TRACING
  4. Check the FIRM box
  5. LOOK AT THE TRACE… you will probably find that there is a business object called when you check the box. If not, it is probably simply the SalesOrder.Update that does the update.

Method Directive, no?

Data directives are way easier and all-encompassing (my preference) [edit: see mea culpa further down], but it skips the BOs.

And with a method directive, you have to think of every way that a person might perform a task. Receipt and mass receipt. New part and duplicate part. Etc.

Not really. They give you access to the underlying table but they won’t keep your PartDtl in sync with your OrderRel. You’ll have to do that manually. Only the Method Directive will do that for you as Tim as noted.

Yes, and all the method directives I inherited simply have some condition and then some C# code that does something like

OrderRel.FirmRelease = true; 
Db.Validate();

I more or less understand tracing, and I’m not trying to figure out how to find the right BO.

I’m trying to figure out what people mean when they say to "use " it!

I can see that my BO needs to be SalesOrder, I guess:

image

But what does one do with it in order to “use the business object” as opposed to changing a database field? I feel like an idiot :neutral_face: but every time I ask “how do I use the BO”, somebody answers “How do I FIND the BO” instead!

Like I said, I must be asking something that’s so obvious to everyone else that my question doesn’t register.

I’m looking forward to suddenly realizing what you’ve all been saying, and I really appreciate the help!

So once you find the Business Object, now look at the Methods that are being called and the parameters going in and out.

Have you checked out the Trace Utility Tool yet? It will show you how to set up the trace and then process it.

I believe you’d need to emulate SalesOrder.Update in that case. You could do so with widgets by adding a couple “Invoke BO Method” widgets with a “Setter” widget.
image

To do so in code would be something like below. Note this is absolutely winged and no promise of accuracy or potential to work. Please google around to get real examples.

using (var soSvc = Ice.Assemblies.ServiceRenderer.GetService<SalesOrderSvcContract>(Db))
{
  int orderNum = 99999; 
  SalesOrderTableset ds = soSvc.GetByID(orderNum);
  foreach (OrderRelRow dr in ds.OrderRel)
  {
    dr.FirmRelease = true;
    dr.RowMod = "U";
  }
  
  soSvc.Update(ref ds);
}
1 Like

@Mark_Wonsil and @rosst thanks enormously. If I understand it then, allowing for syntactical changes which I’m sure I can find, I’m looking at something like:

basically

\\ using [this BO];
{
     \\ here are [some parameters];

     \\ create [this dataset] matching [parameters] from [BO]; 

      \\ foreach [thing] in [this dataset];
           {
                \\ change [these dataset fields];
           }
\\ call [this method] from [BO];
}

Is that basically what I’m trying to do? So instead of just getting the data from the dataset and then changing the Db.WhatEver directly and calling Db.Validate(), the “how” part I was missing is to access the dataset and change it before calling the BO method. As I suspected it seems obvious once it’s explained.

And I won’t ignore the widget methodology - I keep finding that the more I convince people to stick to built-in tools, the less problems we have.

Thank you both and @timshuwy, @Jason_Woods and @JasonMcD . I think I can keep moving forward now, having seen the puzzle pieces in trace, in the BL tool, in @josecgomez ’ cool visualizer and @rosst 's summing up.

2 Likes

Well, right, that was my point. Only method directives sync other tables. I know you all know that, but no one spelled it out, not even Tim, no offense.

As far as data directives being all-encompassing, I did word that badly. They address anything you want to address on that table itself, but not other tables. So they are easier, but often not better.

Data directives

  • Pros: (1) Don’t care what biz obj is doing it - there could be 3 or 4 or 20 that touch this table (PartTran). (2) It is easy to find the name of the table and field you are interested in
  • Cons: (1) Other things don’t get updated that should. (2) If you are a widget BPM-er (me), there are no widgets in the designer for invoking a BO.

Method directives

  • Pros: Uses system logic; has BO widgets; sometimes you can catch stuff way before the user is trying to save the record (like after entering a part number)
  • Cons: (1) Trying to figure out what on earth is the name of the object and method that will do what I want to do. (2) Realizing there are so many objects that do the same thing (line receipt and mass receipt, etc.; un-receiving is slightly different than re-receiving or a new receipt).
3 Likes

Yes, absolutely. You are spot on @JasonMcD. I was stuck in the context of this post but your post is perfect.