JobStatus.MassUpdate doesn't update Job when run from Epicor Function or REST call

Hey everyone,

I am trying to recreate the functionality available in Job Status Maintenance in an Epicor Function. My function is as follows:


The first step (Job Number valid?) verifies the job number passed in exists. If it does, I run JobStatus.GetByID() and use the returned dataset to attempt to update the needed values. I have captured separate traces on Job Status Maintenance for when a job is firmed, released, or engineered
Job Status - Job Engineered.txt (23.6 KB)
Job Status - Job Firmed.txt (24.3 KB)
Job Status - Job Released.txt (23.8 KB). Each scenario is pretty straightforward - you call the appropriate change method (ChangeJobHeadJobEngineered, ChangeJobHeadFirm, or ChangeJobHeadJobReleased depending on the changing value), followed by MassUpdate().

I believe this is exactly what I am doing in the “Update Job” step

try
{

    if (!jobStatusTS.JobHead[0].JobFirm)
    {
        errorMsg += "ChangeJobHeadFirm...\n";
        jobStatusTS.JobHead[0].ToFirm = true;
        jobStatusTS.JobHead[0].JobFirm = true;
        jobStatusTS.JobHead[0].LockQty = true;
        jobStatusTS.JobHead[0].ExtUpdated = true;
        jobStatusTS.JobHead[0].RowMod = "U";
        this.CallService<Erp.Contracts.JobStatusSvcContract>(
            bo =>
            {
                bo.ChangeJobHeadFirm(
                    true,
                    jobNum,
                    ref jobStatusTS);
            });
        errorMsg += "leaving ChangeJobHeadFirm...\n";
    }
    
    if (!jobStatusTS.JobHead[0].JobEngineered)
    {
        errorMsg += "ChangeJobHeadJobEngineered...\n";
        jobStatusTS.JobHead[0].JobEngineered = true;
        jobStatusTS.JobHead[0].RowMod = "U";
        this.CallService<Erp.Contracts.JobStatusSvcContract>(
            bo =>
            {
                bo.ChangeJobHeadJobEngineered(
                    true,
                    jobNum,
                    ref jobStatusTS);
            });
        errorMsg += "leaving ChangeJobHeadJobEngineered...\n";
    }
    
    if (!jobStatusTS.JobHead[0].JobReleased)
    {
        errorMsg += "ChangeJobHeadJobReleased...\n";
        jobStatusTS.JobHead[0].JobReleased = true;
        jobStatusTS.JobHead[0].RowMod = "U";
        this.CallService<Erp.Contracts.JobStatusSvcContract>(
            bo =>
            {
                bo.ChangeJobHeadJobReleased(true,jobNum,ref jobStatusTS);
            });
        errorMsg += "leaving ChangeJobHeadJobReleased...\n";
    }
    
    if (jobStatusTS.JobHead[0].RowMod == "U")
    {
        errorMsg += "Attempting update...\n";
        
        this.CallService<Erp.Contracts.JobStatusSvcContract>(
            bo =>
            {
                bo.MassUpdate(ref jobStatusTS);
            }
        );
        errorMsg += "Update Completed...\n";
    }

}
catch (Exception e)
{
    errors = true;
    errorMsg += e.ToString();
}

I run this method in postman and it appears to run… but the job isn’t released or engineered:


My next step was to remove my function from the process entirely. I invoke the MassUpdate method via the REST API v2 help page. When I run it here, I get the same results - a 200 response but the record isn’t actually updated.


I’m not sure what I’m missing. I’m hoping there isn’t some Epicor black box processing that occurs beyond what is in the trace.

Are you following the trace fully? Sometimes little things that seem innocuous can make the difference between it functioning correctly and not

Hey Aaron,

First off, thanks for taking the time to respond :slight_smile:

To the best of my knowledge I am. I am making the changes to the fields as shown in the trace log. Take the “Job Status - Job Engineered” trace for example. The fields that change between ChangeJobHeadJobEngineered and MassUpdate are JobHead.JobEngineered and RowMod


In my custom code block I set these two fields before running ChangeJobHeadJobEngineered

    if (!jobStatusTS.JobHead[0].JobEngineered)
    {
        errorMsg += "ChangeJobHeadJobEngineered...\n";
        jobStatusTS.JobHead[0].JobEngineered = true;
        jobStatusTS.JobHead[0].RowMod = "U";
        this.CallService<Erp.Contracts.JobStatusSvcContract>(
            bo =>
            {
                bo.ChangeJobHeadJobEngineered(
                    true,
                    jobNum,
                    ref jobStatusTS);
            });
        errorMsg += "leaving ChangeJobHeadJobEngineered...\n";
    }

If I try calling the ChangeJobHeadJobEngineered method before settings these fields, I instead get the error “JobHead has not changed” error in postman.
EDIT - This error was because I moved both RowMod and JobEngineered after the ChangeJobHeadJobEngineered. However, settings JobEngineered after ChangeJobHeadJobEngineered runs but the job isn’t updated.

I ran into something similar with a project I did, where I was setting the fields the way I thought they should be set, and then it returned the message “___ was not updated”…
Those are a little tricky to diagnose unfortunately, but usually have to do with not updating something in the order in which is wants to be updated.
I doubt it’s your code, and I’d look carefully at the trace again to see if there is some method that needs to occur between your calls.

For testing, I’d also get this outside of your try/catch expression. It’s hard to tell where it’s failing inside that

1 Like

Have you try just calling Update instead of MassUpdate? I’ve never seen MassUpdate used in our environment

1 Like

Check below thread, you basically need to have 2 rows when updating, the original one and the updated one.

1 Like

Thank you Tanner! This does update it but when a job is generated from MRP it doesn’t update the job number to the “firmed” job number we have set up in company config.

Boom - worked like a charm thank you Jonathan. The only challenge left for me to figure out is how to get the updated job number when a job generated from process MRP is firmed. But that’s an issue for another day! Thank you so much!

Is there a way I could determine I need 2 rows for a method based on the trace? Or is it safe to assume that any method beginning with “Mass” should have at least 2 rows passed in?

Thanks again!

Thank you to all 3 of you for taking the time out of your day to read through and respond. I really do appreciate it. @tanner your suggestion works flawlessly. I’m marking @Jonathan’s as the solution since my original intent was to use MassUpdate instead of Update. Here is the “final” working code in my REST function. If it changes significantly between now and when the final product is finished I’ll update accordingly.

try
{
    Erp.Tablesets.JobStatusTableset jobStatusTS = null;
    this.CallService<Erp.Contracts.JobStatusSvcContract>(
        bo => { jobStatusTS = bo.GetByID(jobNum); }
    );
    
    // create copy for comparison
    var originalRow = jobStatusTS.JobHead.NewRow();
    BufferCopy.Copy(jobStatusTS.JobHead[0], originalRow);
    jobStatusTS.JobHead.Add(originalRow);
    
    jobStatusTS.JobHead[0].ToFirm = true;
    jobStatusTS.JobHead[0].RowMod = "U";
    this.CallService<Erp.Contracts.JobStatusSvcContract>(
        bo =>
        {
            bo.ChangeJobHeadFirm(
                true,
                jobNum, // this is the original job number - Epicor will update the job number on its own
                ref jobStatusTS);
        });
            
    jobStatusTS.JobHead[0].JobReleased = true;
    jobStatusTS.JobHead[0].JobFirm = true;
    jobStatusTS.JobHead[0].JobEngineered = true;
    jobStatusTS.JobHead[0].ExtUpdated = true;
    jobStatusTS.JobHead[0].RowMod = "U";

    this.CallService<Erp.Contracts.JobStatusSvcContract>(
        bo => { bo.MassUpdate(ref jobStatusTS); }
    );
}
catch (Exception e)
{
    errors = true;
    errorMsg += e.ToString();
}

EDIT
Updated code block. Previous version “worked” but if a job generated by MRP was firmed, it wouldn’t update the Job Number correctly. The code above is working in my environment (10.2.700.9 at the time of this writing). Thanks to everyone who took the time to respond to my initial question as well as @SteveFossey’s post here:

which helped me get on track in getting this to work as intended

The end goal is to allow users to firm, release, and engineer job from within the production planner workbench. I’ll post the final solution once completed. Hopefully this helps someone down the line.

Usually for server logic that makes validations or additional processing it simply looks for a record with RowMod U and goes to work, for new records you can also just send the one row. For updates however it uses the unmodified row to make comparisons as to what changed so it can keep everything in sync.

1 Like