I have created a function that calls a BAQ and does some processing. The BAQ has a date parameter. I have put a BPM on the Update function of UD39. I am not changing any data in UD39, just using the form as a means for the user to enter the date and click the button to run the function. I found some code for getting this to work but it appears that it expects a record to have been updated in the epiview, but I don’t have a record to update.
How do you invoke a BPM (or just the function itself) from the form custom code without an updated data record?
I think I need a bit of help with this. My function was running fine when I executed it using the Schedule Epicor Function, with my date value hard-coded. I want to pass it as a parameter with the REST code but I keep getting an error that the task was canceled, and I have no idea why. The message detail isn’t very specific.
I set up a request and response parameter (although I am not using the response for anything)
I then have my code in my form set up as follows to call this function:
private void epiButtonC1_Click(object sender, System.EventArgs args)
{
// ** Place Event Handling Code Here **
EpiDateTimeEditor ApDate = (EpiDateTimeEditor)csm.GetNativeControlReference("50ee69c5-6d0c-463c-bc8a-5ca4660bb791");
MessageBox.Show("In Call");
string ApiKey = "RestKey";
var restClient = new RestClientBuilder()
.SetDefaultApiKey(ApiKey)
.UseSession(this.oTrans.CoreSession)
.Build();
var functionContent = new RestContent(new { ApplyDate = ApDate.ToString() })
.SetApiKey(ApiKey);
MessageBox.Show("Before Call");
try{
var functionResponse = restClient.Function.Post("MyLibrary", "SetFunction", functionContent, published: true);
MessageBox.Show("After Call");
}
catch (ArgumentException e)
{
MessageBox.Show("Error: {e.Messsage}");
}
}
I put the try and catch here to see if I could catch anything but I doesn’t trigger an exception.
I have been trying to run this with the Schedule Epicor Function process. It properly prompts me for my Apply Date parameter, but the error I am getting is “Parameter should be specified”. I am confused as to where it should be specified since I have it set up in the function signature.
I have removed the try and catch blocks but I still get the error:
Exception executing library ‘MyLibrary’ function ‘’:
System.ArgumentException: Parameter should be specified
Parameter name: id
at Epicor.Functions.FunctionId…ctor(String id) in C:_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Lib\Epicor.Functions.Core\FunctionId.cs:line 21
at Ice.Internal.Task.ScheduledFunction.ExecuteFunction.GetFunctionAdapter(String libraryId, String functionId) in C:_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Task\ScheduledFunction\ExecuteFunction.cs:line 119
at Ice.Internal.Task.ScheduledFunction.ExecuteFunction.RunProcess(Int64 instanceTaskNum, String outputFileName) in C:_Releases\ICE\RL10.2.600.0FW\Source\Server\Internal\Task\ScheduledFunction\ExecuteFunction.cs:line 48
this is server code, you asked question about call on button click, which is client.
What exactly you are trying to achieve at the end? What happens when you click on that button now?
I was trying to get the function running again via the Schedule Epicor Function. I didn’t think about it but I had developer mode on and it was putting me into the execution/parameters (or whatever it is called) for a different function. Once I turned developer mode off it ran (duh).
I have proved that the function will run with the parameter via the Schedule Epicor Function (meaning no errors with the function itself). That being said, my code within the customized form still is throwing the error. I only have one parameter so I was hoping to just do the Anonymous type parameters as described in the help by I am still missing something. Perhaps it has something to do with the way I am trying to get the date entry by the user into the call parameter. I get the value from the control into ApDate then I have this statement:
var functionContent = new RestContent(new { ApplyDate = ApDate.ToString() })
.SetApiKey(ApiKey);
It does not like the “o” in the ToString(). I have tried other ways of not converting it at all and trying to pass a different string variable in but it doesn’t like it. One of the errors I get is
It doesn’t like passing a date type via the query execution parameter so I changed it to a string. This is what I have in my function, which works when I call it via the Schedule Epicor Function.
Here is the function code. Right now it calls the query then just writes information to a file. As I said, this works fine when I schedule it but my call to it from my code does not.
DataTable dt, ResDt;
DataSet ds, ResDs;
string Emp, ResGroup;
decimal NewOHRate = 0;
decimal NewBurdenRate = 0;
int lbrHead = 0, lbrDetail = 0, tranNum = 0;
string path = @"\\myserver.com\EpicorData\LaborRateUpdates_1.txt";
StreamWriter sw = new StreamWriter(path);
var context = Ice.Services.ContextFactory.CreateContext<ErpContext>();
using (var svc = Ice.Assemblies.ServiceRenderer.GetService<Ice.Contracts.DynamicQuerySvcContract>(context))
{
sw.WriteLine("in using " + ApplyDate.ToString());
Ice.Tablesets.DynamicQueryTableset dsQuery = svc.GetByID("OH_Updates");
if (dsQuery != null)
{
Ice.Tablesets.QueryExecutionTableset dsBAQ = svc.GetQueryExecutionParameters(dsQuery);
dsBAQ.ExecutionParameter[0].ParameterID = "ApplyDate";
dsBAQ.ExecutionParameter[0].IsEmpty = false;
dsBAQ.ExecutionParameter[0].ParameterValue = ApplyDate;
//dsBAQ.ExecutionParameter[0].ParameterValue = "06/25/2023";
ds = svc.Execute(dsQuery,dsBAQ);
dt = ds.Tables[0];
int rcount = dt.Rows.Count;
//sw.WriteLine("record count " + rcount.ToString());
foreach (DataRow dr in dt.Rows)
{
Emp = dr["LaborDtl_EmployeeNum"].ToString();
ResGroup = dr["LaborDtl_ResourceGrpID"].ToString();
lbrHead = (int)dr["LaborDtl_LaborHedSeq"];
lbrDetail = (int)dr["LaborDtl_LaborDtlSeq"];
//if this is a project labor record write an error out, else process it
if (dr["LaborDtl_LaborType"].ToString() == "I")
{
var LabDtl = Db.LaborDtl.Where(e=>e.LaborHedSeq == lbrHead && e.LaborDtlSeq == lbrDetail);
foreach (var LLine in LabDtl)
{
//there should only be one line
sw.WriteLine("New burden rate - " + dr["EmpBasic_Name"].ToString() + " Rate= " + LLine.BurdenRate.ToString() + ", Payroll Date=" + dr["LaborDtl_PayrollDate"].ToString() + ", Indirect Code=" + dr["LaborDtl_IndirectCode"].ToString());
}
}
else
{
sw.WriteLine("Non-Indirect Labor Record found: " + dr["EmpBasic_Name"].ToString() + ", Payroll Date=" + dr["LaborDtl_PayrollDate"].ToString() + ", Project=" + dr["LaborDtl_ProjectID"].ToString());
}
}
}
}
sw.Close();
I would start with swapping out the service call with the one for EFX. Don’t hack your way into the context and use the BPM methods.
this.CallService<DynamicQuerySvcContract>(svc=> {
// code here
});
use a using for StreamWriter as well.
Don’t hack your way into the context.
Part of the difference here to bear in mind, that could cause you trouble, is that the server runs the scheduled function with it’s auth and the client runs the function with the clients auth.