Job Operation Update

Hi folks,

We’ve got a couple simple UD columns on the JobOper table that I need to update from the REST API. I saw an Update method in the APi docs for the JobOperSearchSvc but when I run an RowMod = “U” on it, I get BL exception saying that it’s not allowed.

{{
  "HttpStatus": 400,
  "ReasonPhrase": "REST API Exception",
  "ErrorMessage": "Update of JobOper not allowed.",
  "ErrorType": "Ice.BLException",
  "ErrorDetails": [
    {
      "Message": "Update of JobOper not allowed.",
      "Type": "Error",
      "Table": "JobOper",
      "Program": "Erp.Services.BO.JobOperSearch.dll",
      "Method": "JobOperBeforeUpdate",
      "ColumnNumber": 13,
      "LineNumber": 108
    }
  ],
  "CorrelationId": "beef0950-667a-48da-bbe1-56c728eb8f27"
}}

I also tried via the JobEntrySvc and get a similar message:

{{
  "HttpStatus": 400,
  "ReasonPhrase": "REST API Exception",
  "ErrorMessage": "Update not allowed, Engineered and Prevent Changes.",
  "ErrorType": "Ice.BLException",
  "ErrorDetails": [
    {
      "Message": "Update not allowed, Engineered and Prevent Changes.",
      "Type": "Error",
      "Table": "JobAsmbl",
      "Program": "Erp.Services.BO.JobEntry.dll",
      "Method": "valPreventChange",
      "ColumnNumber": 29,
      "LineNumber": 5316
    }
  ],
  "CorrelationId": "1b733478-7cb3-4b16-b6f2-243ba3299c37"
}}

I have an updateable BAQ on a dashboard that has no problems updating that table, so …

What’s the preferred method for updating a job operation? Anyone?

Thanks!

Personally, I expected a lot more people to mention a function by now.

I’m guessing your UBAQ is not using the SearchSvc, since it’s meant to search and not update. Follow a trace for updating the field and duplicate that in a function and you should be golden.

3 Likes

@Mark_Wonsil … you mean run a trace on the client while running the BAQ dashboard?

A simple way would be using the JobEntry.updateExt method in your code to do this.

Essentially this would mimic what your BAQ is doing.

1 Like

I tried the “Update” method, @ridgea (see OP above) … will UpdateExt behave differently in this regard?

The JobEntry might have worked, but it’s still engineered. If you tried to update that field manually in Job Entry, you would have gotten the same error. This is why we trace, so we can see all that has to change. UpdateExt might do that work for you, but you should do a trace and mimic what works.

3 Likes

Yes, stuff like DMT uBaq use the UpdateExt.

UpdateExt combines GetByID / Get New and Update under one roof, just requires the tablesset to be populated in order to figure this out.

I think it also bybass some of the other logics for example ones baked into the update svc of jobEntry that are stopping you from updating your UD fields.

1 Like

So I tried the UpdateExt method and don’t get any error back, even with the two other “onerror” parameters. It returns an OK result, yet no data persists to the DB. On the next query of the Job the custom UD fields are blank as if they were never touched.

So, I guess I need to try a trace via the old client – feel like I’m struggling on this one for some reason.

Here’s my C# in my testbed that looks for and then updates one of the operations…

. . .
var jobOpers = respData.returnObj.JobOper;
var oper = ((IEnumerable<dynamic>)jobOpers).Where(o => (o.AssemblySeq == assemblySeq) && (o.OprSeq == operationSeq)).SingleOrDefault();
if (oper != null)
{
	oper.UD_SetName_c = setName;
	oper.UD_Config_c = configSet;
	oper.RowMod = "U";

	postData = new { ds = respData.returnObj, continueProcessingOnError = false, rollbackParentOnChildError = true };
	respData = EpicorRest.DynamicPost("Erp.BO.JobEntrySvc", "UpdateExt", postData);

	if (EpicorRest.LastCallResult == System.Net.HttpStatusCode.OK)
	{
		result = true;
	}
}
. . .

If it is engineered and you have prevent changes set you also need to give it a change reason or turn that off. We have it off and I can update Jobopers with no issues.

2 Likes

UpdateExt bypasses (almost) all business logic and does a hard save to the DB. If there are any methods that fire after the normal methods, they will not fire with UpdateExt.

Anyone have thoughts as to why the UBAQ works w/o issue on the same JobOper table?

“BeforeImage” most likely.

What you want to do is copy the base row without changes, do your work on the new row, and add that row to your dataset.

The original row is unchanged, and has a RowMod of “”.
The new row is your modified row, and has a RowMod of “U”.

2 Likes

Yeah @klincecum … tried that too.

I have verified before the update that I see the new JobOper object appended to the collection (now +1 with a RowMod = “U”) … still get an OK for the result after calling UpdateExt, yet no errors or persisted change to the data. :frowning:

What BO is your BAQ using for update?

If it is JobEntry.UpdateExt → Are you using Erp.Tablesets.UpdExtJobEntryTableset ?

If so, you will need a row in JobAsmbl and JobHead I believe.

here is how the BAQ did it:

            var JobAsmbl = new Erp.Tablesets.JobAsmblRow
            {
                AssemblySeq = ttResult.JobOper_AssemblySeq,
                Company = ttResult.JobOper_Company,
                JobNum = ttResult.JobOper_JobNum,
            };

            ds.JobAsmbl.Add(JobAsmbl);

            var JobHead = new Erp.Tablesets.JobHeadRow
            {
                Company = ttResult.JobOper_Company,
                JobNum = ttResult.JobOper_JobNum,
            };

            ds.JobHead.Add(JobHead);
2 Likes

Here’s a snippet of code that I use all the time in Epicor Functions:

this.CallService<Erp.Contracts.JobEntrySvcContract>(bo =>
{
	Erp.Tablesets.JobEntryTableset jobTableSet = new Erp.Tablesets.JobEntryTableset();
	jobTableSet = bo.GetByID(this.JobNum);
	
	var jobOperRow = jobTableSet.JobOper.Where(w=>w.Company == Session.CompanyID && 
												w.JobNum == this.JobNum && 
												w.AssemblySeq == this.AssemblySeq && 
												w.OprSeq == this.OprSeq)
										.FirstOrDefault();
	
	if(jobOperRow != null)
	{
	    var originalRow = (Erp.Tablesets.JobOperRow) jobTableSet.JobOper.NewRow(); 
        BufferCopy.Copy(jobOperRow, originalRow); 
        jobTableSet.JobOper.Add(originalRow);
	
		jobOperRow.RowMod = "U";
		jobOperRow.SetUDField("UD_StatutPicked_c", this.StatutPicked);
		
		bo.Update(ref jobTableSet);
	}
});

With JobOper and JobOpDtl, I always add a copy of the unaltered row in the dataset, as @klincecum mentionned earlier.

3 Likes

@mbilodeau … does your snippet via Functions work when Prevent Changes and Create Audit Log are enabled?

image

It’s a major lift for us to tackle right now, converting all our external REST API BO calls to call Functions, so I’d really like to try to get this working using our existing REST API library to update these UD fields on the JobOper table.

I did discover that the working UBAQ is actually calling a BPM (which is doing a very basic, find the oper and edit the fields, then Update) – which works.

I just can’t seem to get the REST API to do the same for our external interface w/o getting the “not allow/prevent changes” error.

I’ve tried a direct edit of the record with a RowMod = “U” on the “Update” and “UpdateExt” methods. I’ve also tried using the BeforeImage variant for both methods as well … all are unsuccessful. BTW, I’ve got a lot of external apps that successfully talk to the REST API in this fashion – this one is really fighting me.

Is it possible the REST API is going to force me to unengineer first, then update then re-engineer?

I’m concerned about responsiveness/performance because all I’m trying to do is save a couple of UD fields … to assist floor production managers on the individual Operation.

1 Like

Let’s see that.

Ask and ye’ shall receive!

1 Like

I have something similar, let me see if I can find it and see if I had to do the unrelease dance or used the db context.

1 Like

Can’t find it, running a test.