Over my head, trying to recreate a screen customization as a BPM

Let me start this post by repeating that I’m not a programmer, but I’ve picked up some programmer skills along my Epicor journey. Enough to be dangerous! However, this current project has quickly gone over my head and I’m wondering if anyone might be able to point me to some sample code or have some pointers so I can learn something new.

Here’s the rundown of what I’m trying to accomplish.

We currently have a screen customization on EndActivity that checks to see if all valued job materials have been issued before completing a quantity. I would like to recreate it as a BPM and tweak it a little bit. So I’ve converted the 1st third to a BPM on LaborUpdate, including converting an SQLDataReader query to a LINQ query (thanks @hkeric.wci & @asmar).

Now I’m trying to display the results of this query in a MessageBox, which I can do but would like to format the results for easier readability.

Here’s what I get:

Here’s what I’d like it to look more like:
image

The original code to do this is:

sCaption = "Materials needing to be issued before completing:\r\n";
sbMsg.Append(string.Format("{0,-15}", "Job #"));
sbMsg.Append(string.Format("{0,-5}", "Asm"));
sbMsg.Append(string.Format("{0,-18}", "Part #"));
sbMsg.Append(string.Format("{0,6}", "Oper"));
sbMsg.Append(string.Format("{0,8}", "MtlSeq"));
sbMsg.Append(string.Format("{0,12}", "Shortage"));

while (dr.Read()) {
		var session = (Ice.Core.Session)oTrans.Session;
		using (var svc = WCFServiceSupport.CreateImpl<Erp.Proxy.BO.JobEntryImpl>(session, Epicor.ServiceModel.Channels.ImplBase<Erp.Contracts.JobEntrySvcContract>.UriPath))
		{
			JobEntryDataSet dsMtls = new JobEntryDataSet();
			dsMtls = svc.GetByID(sJobNum);
			var mtlRow = dsMtls.JobMtl.Select("AssemblySeq=" + iAsm + " and MtlSeq=" + dr.GetInt32(dr.GetOrdinal("MtlSeq")))[0];
				sbMsg.Append("\r\n");
				sbMsg.Append(string.Format("{0,-15}", dr.GetString(dr.GetOrdinal("JobNum"))));
				sbMsg.Append(string.Format("{0,-5}", dr.GetInt32(dr.GetOrdinal("AssemblySeq"))));
				sbMsg.Append(string.Format("{0,-18}", dr.GetString(dr.GetOrdinal("PartNum"))));
				sbMsg.Append(string.Format("{0,6}", dr.GetInt32(dr.GetOrdinal("RelatedOperation"))));
				sbMsg.Append(string.Format("{0,8}", dr.GetInt32(dr.GetOrdinal("MtlSeq"))));
				sbMsg.Append(string.Format("{0,12}", dr.GetDecimal(dr.GetOrdinal("Shortage"))));
		}
} 

Is there a similar way to do this with the results from the Linq query?

var OutStandMtl = (
	from jm in Db.JobMtl.With(LockHint.NoLock)
		join pp in Db.PartPlant.With(LockHint.NoLock)
			on new { jm.Company, jm.PartNum } equals new { pp.Company, pp.PartNum }
			into jmj
			from pp in jmj.DefaultIfEmpty()
	where jm.Company == sCompany && jm.JobNum == sJobNum && jm.AssemblySeq == iAsm 
		&& (pp.QtyBearing == true || pp.QtyBearing == null)  
		&& jm.IssuedComplete == false && jm.BackFlush == false
	select new { jm.Company, jm.JobNum, jm.AssemblySeq, jm.PartNum, jm.Description
		, jm.IUM, jm.RequiredQty, jm.IssuedComplete, jm.RelatedOperation
		, jm.IssuedQty, jm.WarehouseCode, jm.MtlSeq
		, Shortage = (jm.RequiredQty - jm.IssuedQty) }).ToList();

Thanks in advance for any help or guidance!

Your query assumes there will be parts on the Job that do not exist in your part master. If that is not true, the query can be simpler.
Try this (untested so I may have mis-formatted or forgot a parentheses ):

string layoutFormat = "{0,-15} {1,-5} {2,-18} {3,6} {4,8} {5,12}";
string myHeader = string.Format(layoutFormat, "Job #", "Asm", "Part #", "Oper", "MtlSeq", "Shortage"));
string myDetail = "";
foreach (var mtlPart in (
	from jm in Db.JobMtl
		join pp in Db.PartPlant on
		new { jm.Company, jm.PartNum } equals 
		new { pp.Company, pp.PartNum }
			into jmj
			from pp in jmj.DefaultIfEmpty()
	where jm.Company == sCompany && jm.JobNum == sJobNum && jm.AssemblySeq == iAsm 
		&& (pp.QtyBearing || pp.QtyBearing == null)  
		&& !jm.IssuedComplete && !jm.BackFlush
	select new { jm.Company, jm.JobNum, jm.AssemblySeq, jm.PartNum, jm.Description
		, jm.IUM, jm.RequiredQty, jm.IssuedComplete, jm.RelatedOperation
		, jm.IssuedQty, jm.WarehouseCode, jm.MtlSeq
		, Shortage = (jm.RequiredQty - jm.IssuedQty) }))
		{
			myDetail = myDetail + Environment.NewLine = string.Format(layoutFormat, mtlPart.JobNum, mtlPart.AssemblySeq, mtlPart.PartNum, mtlPart.RelatedOperation, mtlPart.MtlSeq, Math.Ceiling(mtlPart.Shortage)));
		}
PublishInfoMessage(myHeader + myDetail, 0,0,"","");

Edit: added Math.Ceiling to round the shortage up to the nearest whole number.

4 Likes

Thanks so much @Jason_Woods, that worked!

image
I do need to check for parts without a part master as our engineering group adds parts-on-the-fly to engineering projects that need to be caught as well.

Thanks again, some format tweaking and then on to the next step.

1 Like