How to send (POST) values to an endpoint when a customer record is added or updated

This is my situation. I need to send a couple values to a specific endpoint when a customer record is added or updated. My thought is to use a GetNewCustomer Method Directive of the Customer table and based on that trigger, use the Execute Custom Code (C#) call of the Post-Processing BPM.

I’ve not done a lot of BPM’s so:

  1. How do I get the specific field values from the Customer table when a record is added or updated.
  2. Is using the Execute Custom Code call the proper way to send/POST my values to the endpoint?
1 Like

I’m assuming this endpoint is outside of Epicor?

Yes. It’s going to through Mulesoft and which ultimately will populate Salesforce.

1 Like

Yes, I have done what you describe with a BPM on the Update method that detects when a row is added or updated. You can use the custom code widget to send a request via HttpClient.

However, I think Automation Studio makes this a lot easier to do if you have that available.

4 Likes

I think I would do this one on a data directive.

But tracing will probably reveal an appropriate update or master update method as well.

If you have functions, I would run a function after your detection code in the bpm.

If not, it’s relatively painless to load up restsharp in bpm land and send a request.

1 Like

I gotta roll @mbayley , can you get him hooked up with some examples.

Should be several on here.

1 Like

Oh, really? Thanks for the tip. I don’t think we have that but, I’ll check.

Did you use C# to do this type of process? I’ve got some basic C# code I created but it keeps telling me declarations aren’t allowed. I have my usings in the proper place … but I can’t declare a variable in the code?

I think you are on too old of a version if your profile is correct.

Yes, all c#
Here’s a small snippet of the code I’m using. Note that you will want your code block to be asynchronous so it doesn’t impede the execution of the business logic.
image

// New http client
using (var client = new System.Net.Http.HttpClient(handler))
{
    // Set token
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "abc123");
    
    // Add company and plant header
    client.DefaultRequestHeaders.Add("Company", CompanyID);
    client.DefaultRequestHeaders.Add("Plant", callContextClient.CurrentPlant);
    
    // New message
    using (var httpRequestMessage = new HttpRequestMessage(new HttpMethod(Method), requestUrl))
    {
        // Set content
        if (string.IsNullOrEmpty(Content) == false)
        {
            httpRequestMessage.Content = new StringContent(Content ?? "", Encoding.UTF8, "application/json");
            Ice.Diagnostics.Log.WriteEntry(Content);
        }
        
        try
        {        
            // Send response
            using (var response = client.SendAsync(httpRequestMessage).GetAwaiter().GetResult())
            {
                // Get content
                var content = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();

                // Set result content
                output = content;

                // Ensure success
                response.EnsureSuccessStatusCode();
            }
        }
        catch (Exception ex)
        {
            throw new BLException("Exception from request to API: " + ex.Message + " | " + output, ex);
        }
    }
}

System.Net.Http.HttpClient may not be available in your version, so you may have to add it as an external library. Just go download the latest .dll from .nuget that is compatible.

4 Likes

Thanks, Michael.

My profile is probably wrong. We’re in the cloud and should be up to date.

So, is this using the Method Directive I described or something else? I looks like a Custome Code call.

Thanks again.

variables, yes, methods, no

2 Likes

This is custom code in a function that is called in a method directive (so I can reuse this code in other similar BPMs)

You can also do this with Change Data Capture (CDC) inside Kinetic. There are a couple of things to set up, but it effectively uses the webhooks process - something is listening for it and then reacts. You are using Mulesoft, but same thing as Epicor’s Workato solution.

You should check out the CDC stuff - it can send a lot and they are adding more rules/events in each release.

2 Likes

We did exactly this - Epicor → Mulesoft → SalesForce.

The approach was to create an audit field to record when specific customer fields were updated. This is triggered by a Customer.Update pre-processing method directive.

The function on a four hourly schedule via the ‘Schedule Epicor Function’ screen.

The function uses a BAQ to return all customer records hat have been updated between the last successful run datetime of the interface and the datetime that the current run started.

The exact fields returned by the query were defined by the integration mapping exercise.

Within the function the BAQ is called an results returned, the results are then converted into JSON and posted to end point in a custom code widget.

WebRequest request = WebRequest.Create (SFURL+"accounts");
var username   = SFUserName ;
var password   = SFPassWord ;
string encoded = System.Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1")
                               .GetBytes(username + ":" + password));
request.Headers.Add("Authorization", "Basic " + encoded);
request.Headers.Add("client_id", SFClientID);
request.Headers.Add("client_secret", SFClientSc);
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
string oResult = Newtonsoft.Json.JsonConvert.SerializeObject(tsRetBAQ);
NoRecs = tsRetBAQ.Tables[0].Rows.Count;
payLoad = oResult;


byte[] byteArray = Encoding.UTF8.GetBytes (oResult);

// Set the ContentType property of the WebRequest.
request.ContentType = "application/json; charset=utf-8";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
Stream dataStream = request.GetRequestStream ();
// Write the data to the request stream.
dataStream.Write (byteArray, 0, byteArray.Length);
// Close the Stream object.
dataStream.Close ();
// Get the response.
WebResponse response = request.GetResponse ();


// Get the stream containing content returned by the server.
dataStream = response.GetResponseStream ();
// Open the stream using a StreamReader for easy access.
StreamReader reader = new StreamReader (dataStream);
// Read the content.
output = reader.ReadToEnd ();

// Clean up the streams.
reader.Close ();
dataStream.Close ();
response.Close ();

I use a UD table to log payload and responses.

As this is a function you can test it using Swagger, which is a plus. Also, you can run the BAQ independently to check that data is been returned.

4 Likes

I use restsharp and newtonsoft for this in BPMs

        // ID variable
        string id = row.WebIDColumn_c;
        
        // JSON body
        var json = new
        {
            CustNum = row.CustNum,
            
        };
        string jsonBody = JsonConvert.SerializeObject(json);

        // Create a new RestClient object
        var client = new RestClient("https://api.yourdomain.co.uk/"); 

        // Create a new RestRequest object
        var request = new RestRequest($"users/{id}/approve", Method.POST);
        request.AddHeader("Content-Type", "application/json");
        request.AddHeader("Authorization", "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes("blahahblah@example.com:435345345345")));
        request.AddParameter("application/json", jsonBody, ParameterType.RequestBody);

        // Send the request and wait for the response
        var response = client.Execute(request);
        if (response.IsSuccessful)
        {
            // Successful response
            Ice.Diagnostics.Log.WriteEntry("Successful response: " + response.StatusCode);
        }
        else
        {
            // Unsuccessful response
            Ice.Diagnostics.Log.WriteEntry("Error: " + response.StatusCode);
        }
        

2 Likes

I haven’t had a chance to play around with CDC. I’ll have to check it out!

2 Likes

I’d be interested in what you find out.

I’ve not either but I did a deep dive researching it so I could interface with our new HR/Payroll system via Workato. Never got back to that project but it’s on the list for this year :wink:

btw - it’s also the background processing for Collaborate which is why we have it turned on and running.

1 Like