Custom code crashing when it hits a BPM

Hello,

I think I’k shooting arrows in the dark, but here it goes. First let me say that the code snipit below is all I have been given access to so far.

Here’s the background. We use custom code to create and load jobs into Epicor. The code below is the part that loads the job.

My problem is that as soon as this code hits a BPM it fails (error below) The BPM is simply a test right now with nothing more than a message box and the code fails before it even gets to that. So something in the code is not liking BPM’s. Is there something special that should be included in the code that lets it process thru BPM’s? The BPM I am using is on Jobentry.update Post-Process

private void CreateJobMtl(SalesOrderDataSet sods, JobEntryImpl jebo, OrderDtlModel line, List<JobMtlModel> boms, List<UpdatedJobModel> updatedJobs = null)
        {
            var dtls = sods.OrderDtl.Select(String.Format("OrderLine = {0}", line.OrderLine));
            if (dtls.Count() > 0)
            {
                var dtl = (OrderDtlRow)dtls[0];
                if (dtl.CreateJob || dtl.JobWasCreated)
                {
                    var rels = dtl.GetOrderRelRows();
                    foreach (var rel in rels)
                    {
                        var jobNum = String.Format("{0}-{1}-{2}", dtl.OrderNum, dtl.OrderLine, rel.OrderRelNum);
                        var jeds = jebo.GetByID(jobNum);
                        var jeds2 = jebo.GetByID(jobNum);
                        var job = jeds2.JobHead[0];
                        var bom = boms.Where(x => !x.FromStock).OrderBy(x => x.ComponentId).ToList();

                        log.Debug(String.Format("Creating job mtls for {0}", jobNum));

                        var updatedJob = updatedJobs != null ? updatedJobs.SingleOrDefault(x => x.JobNum == jobNum) : null;
                        var remainingMtls = updatedJob != null ? updatedJob.RemainingMtls : null;

                        jebo.GetNewJobMtl(jeds2, jobNum, 0);
                        var mtlSeq = 10;
                        while (remainingMtls != null && remainingMtls.Exists(x => x.MtlSeq == mtlSeq))
                        {
                            mtlSeq += 10;
                        }
                        for (var i = 0; i < bom.Count; i++)
                        {
                            var b = bom[i];

                            if (remainingMtls == null || !remainingMtls.Exists(x => x.PartNum == b.PartNumber.Trim() && x.Description == b.Description && x.QtyPer == (decimal)b.Quantity))
                            {
                                var jobMtlRow = jeds2.JobMtl[jeds2.JobMtl.Rows.Count - 1];
                                SetJobMtl(jobMtlRow, b, job, mtlSeq, dtl.OrderLine);
                                jeds.JobMtl.ImportRow(jobMtlRow);

                                //increment mtlsqq by 10
                                mtlSeq += 10;

                                //if seq is already used increment again until not used
                                while (remainingMtls != null && remainingMtls.Exists(x => x.MtlSeq == mtlSeq))
                                {
                                    mtlSeq += 10;
                                }
                            }
                        }

                        var mtlBom = boms.Where(x => x.FromStock).OrderBy(x => x.ComponentId).ToList();

                        log.Debug(String.Format("Creating job mtls (Materials) for {0}", jobNum));
                        var jedsMtl = jebo.GetByID(jobNum);
                        jebo.GetNewJobMtl(jedsMtl, jobNum, 0);
                        for (var i = 0; i < mtlBom.Count; i++)
                        {
                            var b = mtlBom[i];

                            if (remainingMtls == null || !remainingMtls.Exists(x => x.PartNum == b.PartNumber.Trim()))
                            {
                                string vMsgTxt, vMsgType, opMtlIssuedAction;
                                bool multipleMatch, opPartChgCompleted, vSubAvailble;
                                var ipPartNum = b.PartNumber;
                                jebo.ChangeJobMtlPartNum(jedsMtl, true, ref ipPartNum, new Guid(), null, null, out vMsgTxt, out vSubAvailble, out vMsgType, out multipleMatch, out opPartChgCompleted, out opMtlIssuedAction);
                                jebo.ChangeJobMtlRelatedOperation(b.OperationID, jedsMtl);

                                var jobMtlRow = jedsMtl.JobMtl[jedsMtl.JobMtl.Rows.Count - 1];
                                SetJobMtlMaterial(jobMtlRow, b, job, mtlSeq);
                                jeds.JobMtl.ImportRow(jobMtlRow);

                                //increment mtlsqq by 10
                                mtlSeq += 10;

                                //if seq is already used increment again until not used
                                while (remainingMtls != null && remainingMtls.Exists(x => x.MtlSeq == mtlSeq))
                                {
                                    mtlSeq += 10;
                                }
                            }
                        }
                        jebo.Update(jeds);
                    }
                }
            }
        }

The error says “This is a duplicate entry of an existing record”

I guess you cannot add material with the same MtlSeq. But to get more info, can you locate which line is 683 and 772?

I would say there isnt enough information here to help you much.

We dont know what SetJobMtl() does.
We dont know what an “UpdatedJobModel” is or how what is in the data passed

In general, the issue is a duplicate key, most likely of a MtlSeq, but your inner exception should verify that.

Thanks for the replies I have requested more code this morning.

here is the SetJobMtl()


private void SetJobMtl(JobMtlRow jobMtlRow, JobMtlModel b, JobHeadRow job, int mtlSeq, int lineNum)
        {
            jobMtlRow.MtlSeq = mtlSeq;
            jobMtlRow["Number12"] = lineNum;
            jobMtlRow.RelatedOperation = b.OperationID;
            jobMtlRow.PartNum = b.PartNumber.Substring(0, b.PartNumber.Length > 50 ? 50 : b.PartNumber.Length);
            jobMtlRow.QtyPer = (decimal)b.Quantity;
            jobMtlRow.RequiredQty = (decimal)b.Quantity * job.ProdQty;
            jobMtlRow.Description = b.Description;
            jobMtlRow.BuyIt = jobMtlRow.dspBuyIt = b.PurchaseDirect;
            jobMtlRow.Direct = !b.PurchaseDirect;
            jobMtlRow["Character01"] = b.Sticking;
            jobMtlRow["Character03"] = b.GlassCode;
            jobMtlRow["Character04"] = b.GlassType;
            jobMtlRow["CheckBox01"] = b.LVL;
            jobMtlRow["CheckBox02"] = b.TopWedge;
            jobMtlRow.VendorNum = b.GlassSupplier;
            jobMtlRow.LeadTime = b.GlassSupplierLT;

            //ud fields
            jobMtlRow["WidthRoughDec"] = b.RoughWidth;
            jobMtlRow["LengthRoughDec"] = b.RoughLength;
            jobMtlRow["WidthRoughFrac"] = b.RoughWidthFrac;
            jobMtlRow["LengthRoughFrac"] = b.RoughLengthFrac;
            jobMtlRow["ThicknessDec"] = b.Thickness;
            jobMtlRow["ThicknessFrac"] = b.ThicknessFrac;
            jobMtlRow["WidthFinishedDec"] = b.FinishedWidth;
            jobMtlRow["LengthFinishedDec"] = b.FinishedLength;
            jobMtlRow["WidthFinishedFrac"] = b.FinishedWidthFrac;
            jobMtlRow["LengthFinishedFrac"] = b.FinishedLengthFrac;
            jobMtlRow["LengthFinished1Dec"] = b.FinishedLength1;
            jobMtlRow["LengthFinished1Frac"] = b.FinishedLength1Frac;
            jobMtlRow["Sticking"] = b.Sticking;
            jobMtlRow["PanelCode"] = b.PanelCode;
            jobMtlRow["CSRule"] = b.JTrap;
            jobMtlRow["ArchedPart"] = b.ArchedPart;
            jobMtlRow["Solid"] = b.SolidPart;
            jobMtlRow["ArchType"] = b.ArchType;
            jobMtlRow["ArchDropDec"] = b.ArchDrop;
            jobMtlRow["POGlassDesc"] = b.POGlassDesc;
            jobMtlRow["LVL"] = b.LVL;
            jobMtlRow["TopWedge"] = b.TopWedge;
            jobMtlRow["GlassType"] = b.GlassType;
            jobMtlRow["GlassShapeCode"] = b.GlassCode;
            jobMtlRow["FenceVDec"] = b.FenceVertical;
            jobMtlRow["FenceHDec"] = b.FenceHorizontal;
            jobMtlRow["GlassLabel"] = b.GlassLabel;
            jobMtlRow["GlassRadius"] = b.GlassRadius;
            jobMtlRow["Grade"] = b.Grade;
            jobMtlRow["GlassEtchCode"] = b.GlassEGCode;
            jobMtlRow["KochPart"] = b.KochPart;
            jobMtlRow["BoardFeetDec"] = b.BoardFeet;
            jobMtlRow["LinearFeetDec"] = b.LinearFeet;
            jobMtlRow["BoardFeetFrac"] = b.BoardFeetFrac;
            jobMtlRow["LinearFeetFrac"] = b.LinearFeetFrac;
            jobMtlRow["BuildLengthDec"] = b.BuildLength;
            jobMtlRow["BuildWidthDec"] = b.BuildWidth;
            jobMtlRow["BuildLengthFrac"] = b.BuildLengthFrac;
            jobMtlRow["BuildWidthFrac"] = b.BuildWidthFrac;
            jobMtlRow["DoorComponent"] = b.DoorComponent;
            jobMtlRow["Radius1"] = b.Radius1;
            jobMtlRow["Radius2"] = b.Radius2;
            jobMtlRow["RadiusDrop1"] = b.RadDrop1;
            jobMtlRow["RadiusDrop2"] = b.RadDrop2;
            jobMtlRow["ShapeRoute"] = b.ShapeRoute;
            jobMtlRow["Boring1"] = b.Boring1;
            jobMtlRow["Boring1Qty"] = b.Boring1Qty;
            jobMtlRow["Boring2"] = b.Boring2;
            jobMtlRow["Boring2Qty"] = b.Boring2Qty;
            jobMtlRow["Boring3"] = b.Boring3;
            jobMtlRow["Boring3Qty"] = b.Boring3Qty;
            jobMtlRow["Boring4"] = b.Boring4;
            jobMtlRow["Boring4Qty"] = b.Boring4Qty;
            jobMtlRow["Boring5"] = b.Boring5;
            jobMtlRow["Boring5Qty"] = b.Boring5Qty;
            jobMtlRow["Boring6"] = b.Boring6;
            jobMtlRow["Boring6Qty"] = b.Boring6Qty;
            jobMtlRow["Boring7"] = b.Boring7;
            jobMtlRow["Boring7Qty"] = b.Boring7Qty;
            jobMtlRow["Boring8"] = b.Boring8;
            jobMtlRow["Boring8Qty"] = b.Boring8Qty;
            jobMtlRow["Boring9"] = b.Boring9;
            jobMtlRow["Boring9Qty"] = b.Boring9Qty;
            jobMtlRow["Boring10"] = b.Boring10;
            jobMtlRow["Boring10Qty"] = b.Boring10Qty;
            jobMtlRow["Boring11"] = b.Boring11;
            jobMtlRow["Boring11Qty"] = b.Boring11Qty;
            jobMtlRow["Boring12"] = b.Boring12;
            jobMtlRow["Boring12Qty"] = b.Boring12Qty;
            jobMtlRow["Boring13"] = b.Boring13;
            jobMtlRow["Boring13Qty"] = b.Boring13Qty;
            jobMtlRow["Boring14"] = b.Boring14;
            jobMtlRow["Boring14Qty"] = b.Boring14Qty;
            jobMtlRow["GSK1"] = b.GSK1;
            jobMtlRow["GSK2"] = b.GSK2;
            jobMtlRow["GSK3"] = b.GSK3;
            jobMtlRow["GSK4"] = b.GSK4;
            jobMtlRow["GSK5"] = b.GSK5;
            jobMtlRow["GSK6"] = b.GSK6;
            jobMtlRow["GSK7"] = b.GSK7;
            jobMtlRow["GSK8"] = b.GSK8;
            jobMtlRow["GSK9"] = b.GSK9;
            jobMtlRow["GSK10"] = b.GSK10;
            jobMtlRow["GSK11"] = b.GSK11;
            jobMtlRow["GSK12"] = b.GSK12;
            jobMtlRow["GSK13"] = b.GSK13;
            jobMtlRow["GSK14"] = b.GSK14;
            jobMtlRow["GSK15"] = b.GSK15;
            jobMtlRow["GSK16"] = b.GSK16;
            jobMtlRow["ShortChar07"] = b.ProfC1;
            jobMtlRow["ShortChar08"] = b.ProfC2;
            jobMtlRow["ShortChar09"] = b.ProfL1;
            jobMtlRow["ShortChar10"] = b.ProfL2;
            jobMtlRow["Character10"] = b.ExtendedProperties;
            jobMtlRow["ShortChar02"] = b.ParentComponent;
        }

You have the wrong marks for the code formatting - You have ‘’'cs you need ```cs

But it tells me what I need to know. Essentially, there is no logic there, only assignment.

I’d focus on “remainingMtls” and ensure that passed into it exists the Mats you think it does. This will affect the first assignment of MtlSeq

Aside from that I dont necessarily understand what you are doing here and why. Why would you not just use a BOM instead of reinventing the wheel?

Finally, why this:
var jeds = jebo.GetByID(jobNum);
var jeds2 = jebo.GetByID(jobNum);

1 Like

Line 772 in EpicorJobService is just calling the jebo (Job Entry Business Object) Update() method, passing a job entry data set (jeds):

It is the equivalent of hitting JobEntry.Update().
image