Creating an AP Invoice Head with GetNewAPInvHedInvoice REST-API endpoint

I am attempting to add an AP Invoice Head to my Kinetic environment through the RESt-API and I keep getting this error:

Sorry! Something went wrong. Please contact your system administrator. Correlation Id: 9d940985-d629-482c-948f-cf5a004e598a

I contacted the sys admin and we looked for this error in our logs, but couldn’t find it. this happens when trying to hit the endpoint from Swagger as well as from our integration project.

Here’s the invoice head object that’s being sent in:
json1.txt (16.7 KB)

Here’s my context to call the API:

internal async Task CreateInvoices(string groupId, string invoices)
		{
            BuildingRequest += buildServiceRequest;

            var parameters = new BodyOperationParameter[]
            {
                new BodyOperationParameter("ds", invoices),
                new BodyOperationParameter("cGroupId", groupId)
            };

            var request = getNewAPInvHedInvoice(parameters);

            var response = request.Execute();
        }

        private DataServiceActionQuery getNewAPInvHedInvoice(params BodyOperationParameter[] parameters) => new(this, this.BaseUri.OriginalString.Trim('/') + "/GetNewAPInvHedInvoice", parameters);

Can anyone tell me what I’m doing wrong and how I can actually create an AP Invoice head using the REST-API?

I can provide more details if needed. Thanks in advance.

Hey Robert,
In general I steer people to utilizing the REST API but also using Epicor Functions (user defined RPC like endpoints) to do the actual work. The v1 API is more “let’s expose the services over rest” without much consideration for the calling client application. v2 allows the use of Functions, which will give you the opportunity to pass the function what is needed (the dynamic part of the data) and perform the orchestration of the transaction, i.e. create the API invoice head, inside the function.
Typically you’ll want to perform a trace of the transaction through the client first to show what it’s doing and what data is needed. Then, you can build out either your function or calling the appropriate services exactly with those calls. Sometimes weird stuff happens, as you saw, which is why I really recommend the function approach first and foremost.

2 Likes

Please can you give us the extended error in the network tab for DevTools or log the request via Ctrl alt 8 then control alt v after its finished.

I believe you should be able to pass just this and get your return.

{
    "ds": {},
    "cGroupID": "yourGroupID"
}

Hi Aaron,

I am using the API to call this endpoint. We’re not using a client per-se, it’s being done in an integration, I’m manually constructing the AP Invoice head prior to calling the endpoint, the json file I included is what I’m actually sending to the REST API.

I can’t provide anything on the network tab as I’m not doing this from a web app, it’s being done as an integration.

Thanks, I’ll give that a try.

Some additional details:

I am doing this from an integration, not a web app.

Methods creating the invoice head:

internal async Task CreateInvoices(string groupId, IEnumerable<string> invoices)
{
    var apinvoices = new List<APInvoice>();
    try
    {
        var group = await _groupSvc.GetGroup(groupId);

         if (group is null)
             group = await _groupSvc.CreateGroup(groupId);

         foreach (var invoice in invoices)
         {
             var apinvoice = JsonSerializer.Deserialize<OnBaseIntake>(invoice);

             apinvoices.Add(apinvoice.MapToAPInvoice(Company, groupId));
          }

          var vendors = await _vendorSvc.GetVendors(apinvoices.Select(inv => inv.VendorNumVendorID));

          foreach (var invoice in apinvoices)
              invoice.TermsCode = vendors?.FirstOrDefault(v => v.VendorId == invoice.VendorNumVendorID)?.TermsCode;

          var ds = new APInvoiceTableset
          {
              APInvHed = apinvoices
          };

          var json = JsonSerializer.Serialize(ds);

          await Ctx.CreateInvoices(groupId, json);
      }
      catch(Exception ex)
      {
          throw;
      }
}
internal static APInvoice MapToAPInvoice(this OnBaseIntake source, string company, string groupId) => new()
{
	Company = company,
	GroupID = groupId,
	InvoiceNum = source.InvoiceNum,
	VendorNumVendorID = source.VendorNum,
	InvoiceAmt = decimal.Parse(source.InvoiceAmount),
	DebitMemo = false,
	RateGrpCode = "RateType1",
	CurrencyCode = "USD",
	Posted = true
};

Even more reason to take a look at what Aaron is suggesting. Why complicate your integration client with Kinetic-specific code? Pass a Json string that makes it easy on your client and then put the work of the Invoice creation in the Epicor Function. Bonus: you’ll cut down the number of calls over the wire and make your integration faster.

1 Like

Doesn’t that kind of eliminate the purpose of an integration though? We have considered doing an Epicor Function that does all the work, but we decided against it. I see the benefit of doing it that way though.

Appologies, I didn’t fully grasp what you were telling me. I was half asleep and had been trying to figure out a solution on my own. We had looked at doing an Epicor Function before, but decided against it since we felt that it was eliminating the purpose of an integration. I like your recommendation much better than what we’re doing now, which is adding the invoice through DMT.

1 Like

What is your current integration methods? E.g custom built website?

What is your end goal? Explain in great detail so we can determine a suitable solution.

What version are your end users currently using? This so we can build a solution around this version and make sure its upgrade compatible.

It’s just another tool in the chest, and a way to do abstractions. A very powerful one at that.
Nice place to keep your logic contained, and do it on the server.

I try and do anything I can on the server, instead of any type of client. Do just what you need
in the client, and pass the data up for processing.

Very Tidy.

2 Likes

The way it’s been requested is that we have a document management system that, when it sees that an invoice is ready to be created, it creates a JSON file in one of our network folders. The integration has a worker service that runs once, or multiple times daily(final decision hasn’t been made yet on how often), to sweep that folder to check for new files.

When it picks up a new file, it transforms that JSON file into a collection of APInvoiceHed objects. Creates the “ds” object for the body parameter for GetNewAPInvHedInvoice.

The end goal is to basically use this RPC method to insert these items into our Kinetic DB.

Our users are currently using ERP10.

Whats your DMS?

Please can we see the JSON output youve generated.

Is the JSON output triggered from within epicor?

You need to explain in greater detail the steps.

Example
Customer requests invoice via email
Json file generated
Json file is grabbed using DMS
DMS processes json file via rest module.

I would have that service create just what you need to pass that off to the server.
Parse it there and do everything else you need.

Don’t be afraid to change your architecture if there is a better way. You can pay for it
now or pay for it later, with interest :slight_smile:

2 Likes

The DMS is OnBase

This is the JSON that’s generated from OnBase

{
  "poNumber": "",
  "invoiceNumber": "test01",
  "invoiceDate": "10/21/2022",
  "freight": "14.90",
  "FreightGLCode": "INFRGHT",
  "MiscGLCode": "",
  "TaxCode": "",
  "misc": "0.00",
  "taxAmount": "0.00",
  "totalAmount": "346.50",
  "vendorId": "A-ZM",
  "vendorName": "A-Z Metals",
  "surcharge": "",
  "glOverride": "INFRGHT",
  "invoiceStatus": "MISSING RECEIPT",
  "docHandle": "1605438",
  "poType": ""
}

Will more than likely go that route.

1 Like

Cool, I’m not suggesting you just blindly take my advice, but to evaluate your options.

Lot’s of smart cookies here.

Run this through Postman or Insomnia on your given method. Are you using v2 or v1…