Help with my first function

I was having an issue with a UD field not saving the data to the database. That thread is here.

Application Studio View not saving data for UD field - Kinetic ERP - Epicor User Help Forum

Based on the excellent information I got in the response to that thread I’m working on setting up a function to save that data to the database. And BOOM I have issues :roll_eyes: with my first stab at functions.



I’m getting an error that the ds can’t see my UD field in the nonconf table. I can view that field in SQL.

I’m sure it has something to do with it being a UD field and me not doing something correctly :slight_smile: If I do a contrl & Space after putting in row.ins it doesn’t even find my field.

row["InspecTime_c"] = whatever;

Things like NonConfRow do not get updated with a regen. They won’t show up.

1 Like

Hello Tammy,
Hope you’re well.

I’m about to catch a flight, so I don’t have too much time at the moment, but you can solve this quicker by avoiding code all together. If you review the details I provided in my previous response, I was suggesting using widgets inside of your function to solve this issue. As mentioned, you would just need to get GetByID, then add the change for the InspectTime_c, and finally Update. It will be a few widgets and probably faster/easier if you’re more comfortable with a declarative solution.

I can assist on Monday more if needed, good luck!

1 Like

You might need to try something like this:

x.SetUDField<System.Boolean>(“CheckBox05”, tt.CheckBox01);

Check if .row.SetUDFIeld is an option. If so, give this a try.

1 Like

Here is my stab at this using widgets.



Not sure where to place this:
5 - Next, update your dataset (there are several ways to do this), and update RowMod → ‘U’, and InspecTime_c → Input 1.

In application studio I have this.

Hello Tammy,
Hope you’re well.

Apologies for the large delay here.

I wanted to go ahead and do a writeup for this post, since I think it is valuable to anyone stumbling across it.

Here’s the solution:
In Application Studio, you will need to call the function:
Trigger:

And pass the parameters to the function:


You can remove the kinetic-messager-handler for a production deployment, I only had it there for debugging purposes.

Now you’ve hit the function, so let’s look at that:

References-Tables:

References-Services:

Security: Add the company this will be operating within to the “Authorized Companies” list.

For the function itself, be sure to add the parameters to the “Request” list as we discussed earlier. This is what is being passed from Application Studio to our function.

The function itself is simple, just a code block. I will explain why I used only code instead of declarative solution later:

This is the code you will put into that Execute Custom Code block:

//Andrew I, 2/11/26
this.CallService<Erp.Contracts.NonConfSvcContract>(
  nc =>
  {
    var NonConfTS = nc.GetByID(tranID); 
    
    var NonConf = NonConfTS.NonConf.FirstOrDefault();
    var newNonConf = (Erp.Tablesets.NonConfRow) NonConfTS.NonConf.NewRow();
    BufferCopy.Copy(NonConf, newNonConf);
    NonConfTS.NonConf.Add(newNonConf);
    
    NonConf.RowMod = "U";
    NonConf["InspecTime_c"] = InspectTime;

    nc.Update(ref NonConfTS); 
  });

If you do a full trace of the process, you will see a “PreUpdate” is called prior to the update. Upon reading the description of the method: PreUpdate - “This method does: 1 - Returns a record in the LegalNumGenOpts datatable if a legal number is required for this transaction. The RequiresUserInput flag will indicate if this legal number requires input from the user. If it does, the LegalNumberPrompt business objects needs to be called to gather that information. This method should be called when the user saves the record but before the Update method is called.”

If this is relevant to you, just add

nc.PreUpdate(ref NonConfTS);

before the update.

Once you’re done, just go to the “Actions” and “Promote Library to Production” so Application Studio can hit your function.

That’s it, you’re done. Congrats on your first function!


Some extra information and breakdown for those interested:

I was unable to get the solution working without code as mentioned earlier, and opted for a full code solution on the Function end.

Upon testing via the REST API Help page, I noticed when I was attempted to hit the NonConf update directly it wasn’t working when I was passing my dataset. When looking through the data that is passed to the update method in the google dev tools (F12 to open), I saw this:

Epicor passes two rows, and it does this in several places in the system. One row contains the dirty changes (ie changes uncomitted to the DB), and the other is the original row. This is generally done so the program can compare the changes, and only push the diff of the changes. When I copied this payload DS, and passed it to the NonConf.Update function in the REST API Help interface, I saw method didn’t error.

Therefore, in order hit this NonConf.Update, we need to do pass the dirty and original row. That is why in the code we have this section:

    var NonConf = NonConfTS.NonConf.FirstOrDefault();
    var newNonConf = (Erp.Tablesets.NonConfRow) NonConfTS.NonConf.NewRow();
    BufferCopy.Copy(NonConf, newNonConf);
    NonConfTS.NonConf.Add(newNonConf);

I mention the REST API Help interface several times. To access that, follow this format: https://[your epicor server]/EpicorERP/api/help/v2/

You can find this server link/path inside of your Epicor client on the top right:
image

Lastly, for those who are interested in writing more code, another important detail is the way to “call” a BO differs in Function vs BPMs. As you can see in this function, the BO is called like so:

this.CallService<Erp.Contracts.NonConfSvcContract>(
  nc =>
  {

This differs from the syntax in a BPM which would look more like this:

var NCsvc = Ice.Assemblies.ServiceRenderer.GetService<Erp.Contracts.NonConfSvcContract>(Db);

Source - Functions data context - #8 by SAD
Sergey Davydkin is a former Epicor employee who helped build Epicor Functions. He talks more about this concept here for those who are interested.

Feel free to let me know if you have any other questions. Have a great day!

EDIT -
Another note here, in the code you will notice this:

    NonConf.RowMod = "U";
    NonConf["InspecTime_c"] = InspectTime;

As @klincecum mentioned above, for UD fields, you need to access them slightly differently to update the data. So for non-UD fields, you can access them like a normal ORM. For UD fields, you need to access them like you would access the value of a dictionary.

In addition to that, when making updates, you will always need to add
“NonConf.RowMod = “U”;”. There are 3 options. A - add, U - update, D - delete. The RowMod in the dataset tells the update there are changes to be committed to the DB. So if you are ever calling “Update” and nothing is happening, ensure the RowMod value is being set.

3 Likes

Actually CallService is available in BPMs now if you would like to use it.

1 Like