Edit Job Assemblies programmatically

Hello,

I’ve been trying to edit a job assembly with its operations and materials from an external program.
I was able to do so by desablin EncorceConstraints on the JobEntryDataset. When I wanted to do it with the constraints by using the appropriate BO methods but I got this message:

Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.

Table: JobAsmbl
Company=‘MET’ JobNum=‘037794’ AssemblySeq=‘8’ SysRowID=‘00000000-0000-0000-0000-000000000000’: ForeignKeyConstraint HeadAsmbl requires the child key values (MET, 037794) to exist in the parent table.

Am I doing something wrong?

 using (var jobEntryBO = WCFServiceSupport.CreateImpl<JobEntryImpl>(session, JobEntryImpl.UriPath))           
        {                
            try
            {
                var jobNum = "037794";

                var newJobEntryDataSet = new Erp.BO.JobEntryDataSet();
                jobEntryBO.GetNewJobAsmbl(newJobEntryDataSet, jobNum);
                newJobEntryDataSet.JobAsmbl[0].PartNum = "C-CANTLIV";
                newJobEntryDataSet.JobAsmbl[0].Description = "Test Assembly C-CANTLIV";                    
                jobEntryBO.InsertNewJobAsmbl(newJobEntryDataSet, jobNum, 8, 3, -1);
                jobEntryBO.Update(newJobEntryDataSet);

...
}

thnx!

Did you perform a trace of this transaction?
If I was to guess, you need to get the parent Job first, then add to it.

When I do so I get another error:
Object reference not set to an instance of an object.
I did it like this:

var parentJob = jobEntryBO.GetByID(jobNum);
jobEntryBO.InsertNewJobAsmbl(parentJob , jobNum, 8, 3, -1);
jobEntryBO.Update(parentJob );

Is that what the trace revealed the series of calls to be?

I’m not sure how I can perform a trace of this transaction. I’m just assuming the series of calls are like that. I can’t find any example in the forum or in the documentation. is it on the log?

Typically this would be done by using the trace log and performing the transaction (or having someone else who is knowledgeable about job entry perform it) and then replicate the calls in your code.

We don’t use job entry, so I can’t say for sure, but that would be the way to find out. It’s pretty tough to guess what calls/field/order things are happening in.

1 Like

Ok I will proceed like that from now on, thanx for the informations! I have the serverlog enabled.

This is probably best done with a client trace vs. a server trace (since the server trace probably includes a lot of noise). Let me know how it goes!

Thanx again for the valuable information, I didnt know It was possible to activate the client log! Letting you know as soon as I can perform the operations properly.

1 Like

Good morning, @Aaron_Moreng, so I’ve done what you suggested. I followed the client trace and replicated the calls. However, I have a little error. Maybe I’m not starting my code properly.

                var jobNum = "037795";
                var partNum = "TraceTest";          
                
                var jobEntryDataSet = jobEntryImpl.GetByID(jobNum);
                jobEntryImpl.InsertNewJobAsmbl(jobEntryDataSet, jobNum, 0, 0, 0);
            
                jobEntryImpl.CheckChangeJobAsmblParent(0, jobEntryDataSet);
                var vSubAvail = false;
                var vMessageType = "";
                var vMsgText = "";
                var multipleMatch = false;
                jobEntryImpl.CheckPrePartInfo(jobEntryDataSet,ref partNum, Guid.Empty, true, string.Empty, string.Empty,out vMsgText,out vSubAvail,out vMessageType, out multipleMatch);
                jobEntryImpl.ChangeJobAsmblPartNum(jobEntryDataSet);                  

                jobEntryImpl.Update(jobEntryDataSet);

the error is: PartNum cannot be empty.

@Aaron_Moreng Finally I was able to do it without violating any constraint by inspiring myself from this post. Here is the code:

                var jobNum = "037795";
                var partNum = "TraceTest";      
                
                var jobEntryDataSet = jobEntry.GetByID(jobNum);

                jobEntry.InsertNewJobAsmbl(jobEntryDataSet, jobNum, 0, 0, 0);

                DataRow toInsert = jobEntryDataSet.Tables["JobAsmbl"].Rows[jobEntryDataSet.Tables["JobAsmbl"].Rows.Count-1];
             
                toInsert.BeginEdit();
                toInsert["PartNum"] = partNum;
                toInsert["Description"] = "Description Test";  
                jobEntry.Update(jobEntryDataSet);

Do you think it is a good way or I should focus on making work the calls found in the trace?

There is only one issue with the record. I think… The BomSequence doesnt seem to follow the pattern of the existing Assemblies.
image

is it a problem?? I thought it would be 8.

Best practice is to follow the calls found in the trace. Sometimes, seemingly innocuous calls are actually vital in setting different fields properly within the dataset prior to updating. I am not familiar with Job Entry or really anything related to this business object, but I can tell you that you’ll have the best luck by recreating what you see in the trace.
There is a nice tool that @josecgomez and @jgiese.wci built GitHub - jose-josh-do-dev/EpicorTraceDiffer: Allows you to Parse and process Epicor Trace Files Easily. which is great for interpreting trace logs more clearly.

2 Likes

thanx @Aaron_Moreng, thats an amazing tool. I did exactly follow what was in the trace just like before and I still have the same error. Apparently the PartNum of the assembly isn’t set.

                var jobNum = "037792";
                var assemblySeq = 0;
                var bomLevel = 0;
                var priorAssemblySeq = 0;

                jobEntry.ValidateJobNum(jobNum);
                var jobEntryDataSet = jobEntry.GetByID(jobNum);

                jobEntry.InsertNewJobAsmbl(jobEntryDataSet, jobNum, assemblySeq, bomLevel, priorAssemblySeq);

                var ipNewParent = 0;

                jobEntry.CheckChangeJobAsmblParent(ipNewParent, jobEntryDataSet);

                var partNum = "SubAssemblyTest";
                var sysRowID = Guid.Empty;
                var skipXRefUpdate = true;
                var xrefPartNum = "";
                var xrefPartType = "";
                var vMsgText = "";
                var vSubAvail = false;
                var vMsgType = "";
                var multipleMatch = false;

                jobEntry.CheckPrePartInfo(jobEntryDataSet,ref partNum, sysRowID, skipXRefUpdate, xrefPartNum, xrefPartType,out vMsgText, out vSubAvail, out vMsgText, out multipleMatch);
                
                jobEntry.ChangeJobAsmblPartNum(jobEntryDataSet);
                
                jobEntry.Update(jobEntryDataSet);

Is there anything to do with the callContext?

No shouldn’t be related to anything with callcontext…

Do you know at which method it’s failing? You’re gonna have to do the debugging yourself unfortunately. You can step through with VS (I assume this is an external app). Need to see which method is throwing that exception

It fails at the update and give me a Business Logic Error from Epicor.ServiceModel saying PartNum can’t be empty.
at Epicor.ServiceModel.Channels.ImplBase`1.ShouldRethrowNonRetryableException(Exception ex, DataSet[] dataSets)
at Erp.Proxy.BO.JobEntryImpl.Update(JobEntryDataSet ds)

I fixed this error by changing the value of the PartNum column in the last inserted row like I did before. I got another business error saying I need the description. So after analysing the trace another time. I realised that some stuff are missing between the JobEntry BO calls. At any place the PartNumber is changed but I see it after in the DataSet that is used as a parameter. I assumed that the fields of the JobAsmbl Table are filled somewhere else. Any Idea which BO could takes care of that?

That Trace Diff tool actually shows all the BOs that are called. I’d use that PLUS the original trace log to see what BO is setting those fields. It’s probably being called inbetween the jobEntry BO

1 Like