MRP Suggestions for Unfirm Releases

MRP is occasionally generating suggestions for unfirm order releases. We currently have 81 unfirm releases without jobs but 97 other releases have had jobs created. It was our understanding based on information from consultants and what we saw online that marking a release as unfirm would prevent MRP from generating suggestions.

Any insight is welcome. I’d be happy to provide whatever information I can.

Unless things have changed, yes that’s right.

Have you run MRP as regenerative since then? I ask because I wonder if the 97 are old jobs that have not been deleted yet.

Our MRP runs regenerative each morning. Our scheduler apparently firmed the suggestions without knowing to be concerned whether the release was firm (which he shouldn’t have to consider).

Well, that’s odd, alright.

Are you sure they’re not based on forecasts? We had unfirm jobs in time phase that we couldn’t account for, and THAT was how we learned how forecasts worked.

1 Like

There are no forecasts for any of the parts in question.

Maybe a dumb question, but are the suggestions for THOSE releases or are they suggestions to change the original jobs, based on other releases’ demand?

We had a situation where we postponed some orders and unlinked their jobs, but left the jobs in place; and then based on other demand for the same parts, MRP created suggestions for changes to existing jobs instead of creating new jobs. We caught it because a given sales order had a linked job with a job number that wasn’t similar to the SO, and a quantity that didn’t match.

The releases are all marked Make Direct and OrderRel.ReqQty, JobProd.ProdQty, and JobHead.ProdQty all match. That seems to indicate the jobs are specific for those releases.

Some companies make BPMs that update OrderRel Firm flag based on a UD Field “Firm” in the OrderHed table… while this sounds easy, there is one complication. Simply updating the OrderRel table does NOT update the PartDtl table, which is what MRP uses to determine if it should create jobs. PartDtl also has a firm flag.
So… check that data table to make sure that OrderRel and PartDtl match.


Oh my goodness…I think that might explain a few things. I inherited some serious customization and I’ve never been able to figure out why some of the MRP suggestions are all over the map. Not from BPMs, but we have over 2000 lines of code added to Sales Order Entry.

We firm the release upon “ready to fulfill” check-boxing, upon changing sites, and at several other events. I haven’t seen any reference to PartDtl in the code, and I thought it and (I think) SugPart (?) were just automatically (and magically) supposed to be perfect…

Well, that definitely gives me something to investigate this weekend. A quick check shows that OrderRel and PartDtl do not match, but it doesn’t appear to be consistent. Under advisement from our consultants, one of the first BPMs I made was indeed to
default OrderRel.FirmRelease to false to prevent MRP from hitting the orders, though there was never mention of PartDtl. I’m definitely curious as to how this is affecting the creation and relationship of PartDtl records.

“Some companies”? Oddly, I think I see this happening on 1 out of every 3 clients. Someone wrote a “simple” BPM to update the OrderRel, but all of the demand screen don’t match…


With some testing, the PartDtl records are indeed being created with FirmRelease true. Would an In-Transaction directive on PartDtl to set FirmRelease of added records where OrderRel <> 0 be sufficient? Would that cause issues?

I find it odd this isn’t part of the recommendation from consultants if it’s such a common requirement.

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;


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.


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?


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.

1 Like

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