ARInvoiceSvc API trouble

I am having some issues regarding the ARInvoiceSvc. I am trying to use the update method and I am getting a null reference exception.

RestClient client = new RestClient("https://server/epicor/api/v1/Erp.BO.ARInvoiceSvc/");
    client.Authenticator = new NtlmAuthenticator();

    var GetInvoice = new RestRequest("GetByID", Method.POST);
    GetInvoice.AddHeader("Content-Type", "application/json");
    var GetInvoiceParamObj = new JObject();
    GetInvoiceParamObj.Add(new JProperty("invoiceNum", "660772"));
    GetInvoice.AddParameter("ds", GetInvoiceParamObj, ParameterType.RequestBody);

    IRestResponse GetInvoice_response = client.Execute(GetInvoice);

    dynamic json = JValue.Parse(GetInvoice_response.Content);

    json.returnObj.InvcHead[0].Company = "LP";
    json.returnObj.InvcHead[0].ShortChar03 = "RG0014";
    json.returnObj.InvcHead[0].ShortChar04 = "HAJOCA";
    json.returnObj.InvcHead[0].ShortChar06 = "TEST2";
    json.returnObj.InvcHead[0].CheckBox03 = false;
    json.returnObj.InvcHead[0].CheckBox06 = false;
    json.returnObj.InvcHead[0].RowMod = "U";

    // strong typed instance 
    var jsonObject = new JObject();
    dynamic ds = jsonObject;
    ds.ds = json.returnObj;
    //ds.Add(new JProperty("continueProcessingOnError", true));
    //ds.Add(new JProperty("rollbackParentOnChildError", false));

    var UpdateInvoiceTable = new RestRequest("Update", Method.POST);
    UpdateInvoiceTable.AddHeader("Content-Type", "application/json");
    UpdateInvoiceTable.AddParameter("ds", ds, ParameterType.RequestBody);
    IRestResponse UpdateInvoiceTable_response = client.Execute(UpdateInvoiceTable);

    if (UpdateInvoiceTable_response.ResponseStatus == ResponseStatus.Completed)
    {
        //return true;
    }
    else
    {
        //return false;
    }

When I change this to use the UpdateExt Method (not entirely sure what the difference is, or its impact) It will work if I uncomment out the ds.add lines.

Although it works, it returns an exception message that I have no idea what it means.
BusinessObjectException
Message No.:1
Description: Tax Service records are committed. Update not allowed.
Program: Erp.Services.BO.ARInvoice.dll
Method: OnChangeofLineQty
Line Number: 23459
Column Number: 17

Any help would be appreciated.

EDIT:

Also, here is the stack trace if you need it.

System.NullReferenceException: Object reference not set to an instance of an object.

at Erp.Services.BO.ARInvoiceSvc.InvcHeadBeforeUpdate() in C:_Releases\ERP\UD10.2.300.3\Source\Server\Services\BO\ARInvoice\ARInvoice.cs:line 16208
at Ice.Services.Trace.TablesetProfilingCollector.DoRowEventTrace(String tableName, String methodName, Int32 rowCount, Action action) in c:_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Services\TablesetProfilingCollector.cs:line 144
at Ice.TablesetBound3.UpdateRow(IceDataContext dataContext, Int32 tableNum, IIceTable table, IceRow updatedRow, IceRow originalRow, IColumnUncensor uncensor, TablesetProfilingCollector parentTraceCollector) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 1263 at Ice.TablesetBound3.WriteTable(IceDataContext dataContext, Int32 tableIndex, IIceTable table, TablesetProfilingCollector parentTraceCollector) in c:_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 974
at Ice.TablesetBound3.InnerUpdate[TUpdater](IceDataContext dataContext, TFullTableset tableset) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Services\TablesetBound.cs:line 874 at Erp.Services.BO.ARInvoiceSvc.Update(ARInvoiceTableset& ds) in C:\_Releases\ERP\UD10.2.300.3\Source\Server\Services\BO\ARInvoice\ARInvoice.Designer.cs:line 4233 at Erp.Services.BO.ARInvoiceSvcFacade.Update(ARInvoiceTableset& ds) in C:\_Releases\ERP\UD10.2.300.3\Source\Server\Services\BO\ARInvoice\ARInvoiceSvcFacade.cs:line 10069 at Ice.Hosting.RestApi.OperationInvokeHelper.CallInvoker(IceDataContext dataContext, Type svcType, MethodInfo mi, Object[] inputs, Boolean isRoot) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Hosting\ServiceCaller\OperationInvokeHelper.cs:line 292 at Ice.Hosting.RestApi.OperationInvokeHelper.MakeServiceCall(IceDataContext dataContext, Type svcType, MethodInfo mi, Object[] parameters) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Hosting\ServiceCaller\OperationInvokeHelper.cs:line 248 at Ice.Hosting.RestApi.OperationInvokeHelper.CallCustomMethod(String serviceName, MethodInfo mi, Object[] paramList) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.Ice\Hosting\ServiceCaller\OperationInvokeHelper.cs:line 212 at Epicor.RESTApi.DataSources.IceServiceCaller.CallCustomMethod(TypeMapping typeMapping, ContextInfo context, String methodName, Object inputObject) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.RESTApi\DataSources\IceServiceCaller.cs:line 272 at Epicor.RESTApi.Controllers.CustomActionController.CustomMethod(Object input) in c:\_Releases\ICE\RL3.2.300.0\Source\Framework\Epicor.RESTApi\Controllers\CustomActionController.cs:line 25 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary2 arguments, CancellationToken cancellationToken)
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ApiControllerActionInvoker.d__0.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Filters.ActionFilterAttribute.d__5.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.ActionFilterAttribute.d__0.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Controllers.ActionFilterResult.d__2.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Filters.AuthorizationFilterAttribute.d__2.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Web.Http.Dispatcher.HttpControllerDispatcher.d__1.MoveNext()
— End of stack trace from previous location where exception was thrown —
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

You may want to take a look at the Epicor Event log. It might contain more info to help resolve this issue. Any reason your not using the oData methods?

UpdateExt internally makes GetByID and then compares all fields in the object and replaces them with new values, if change found. Then it calls Update.
So you can send only changed fields to UpdateExt (and key fields to identify what item to retrieve).

I can;t say why your Update example does not work, something is missing that InvcHeadBeforeUpdate() expects.

Hey Josh,

Hopefully this helps, the update methods in Epicor sometimes require 2 datasets the first being the original InvcHead row with no modified values, then a second row InvcHead[1] with the modified dataset with RowMod = ‘U’.

So we are looking at for you

Dataset: {
   InvcHead: [ 
   { 
      *UNMODIFIED copy of the datarow*
   }, 
   {
      *MODIFIED copy of the datarow with RowMod U*
   }]
}

The reason this occurs as it appears that many standard Update methods in Epicor have logic to .compare() the datarows to find what fields have been modified. As there is only one datarow the method throws a ‘NullReferenceException’ error as it cannot make this comparison… There is no indication on the API help to tell you this, you just kinda have to know what is going on behind the curtain to figure out why.

In regards to the behaviour of UpdateExt, this method behaves differently as it has completely seperated logic which doesn’t make these .compare() errors. However it is wiser in some cases to use Update() or UpdateMaster() logic as often these have alot more logic to linked processes.

Again, this may not solve your issue, but it is certainly to me throwing red flags of an Update method that requires 2 datarows in the update method.

This makes a lot of sense. Thank you for the response! I will have to give this a shot.