Background on me: 15+ years in IT, but not a dev by any means.
Our environment: Kinetic 2024.2 | Cloud
I’m attempting to use a function to automate serial number matching. In this case, the parent and child serial numbers always literally match, so if the assembly is S/N 11111 then material is also S/N 11111. There’s a BPM that fires when material is issued to a job which automates serial number assignment (which works) and then calls this function to do the matching.
This is my current code using dynamic classes.
using Newtonsoft.Json;
using RestSharp;
// Input values - these are passed to the function as request parameters
string ipSerialNo = this.ipSerialNo.ToString();
string ipPartNum = this.ipPartNum.ToString();
string ipRevNum = this.ipRevNum.ToString();
string ipJobNum = this.ipJobNum.ToString();
int ipAssemblySeq = Convert.ToInt32(this.ipAssemblySeq);
// Base URL
string baseUrl = "https://.../api/v2/odata/000000/Erp.BO.SerialMatchingSvc/";
// API Key
string apiKey = "...";
// Basic Auth
string username = "...";
string password = "...";
// ChangeSerialNum
var client1 = new RestClient(baseUrl + "ChangeSerialNum");
var request1 = new RestRequest(Method.POST);
request1.AddHeader("Content-Type", "application/json");
request1.AddHeader("Authorization", $"Basic {basicAuth}"); // Basic Authentication
request1.AddHeader("X-API-Key", apiKey); // API key using X-API-Key header
request1.AddJsonBody(new
{
ipSerialNo,
ipPartNum,
ipRevNum,
ipJobNum,
ipAssemblySeq
});
var response1 = client1.Execute(request1);
if (!response1.IsSuccessful)
{
throw new Exception($"API call to ChangeSerialNum failed: {response1.Content}");
}
dynamic changeSerialNumResponse = JsonConvert.DeserializeObject<dynamic>(response1.Content);
Console.WriteLine($"ChangeSerialNum Response: {JsonConvert.SerializeObject(changeSerialNumResponse)}");
// GetAvailableToMatch
var client2 = new RestClient(baseUrl + "GetAvailableToMatch");
var request2 = new RestRequest(Method.POST);
request2.AddHeader("Content-Type", "application/json");
request2.AddHeader("Authorization", $"Basic {basicAuth}");
request2.AddHeader("X-API-Key", apiKey);
request2.AddJsonBody(new
{
ipType = "mtl",
ds = new
{
AvailToMatch = new object[] { },
SerialMatchAsmbl = new object[] { },
SerialMatchHdr = changeSerialNumResponse.returnObj.SerialMatchHdr,
SerialMatchMtl = changeSerialNumResponse.returnObj.SerialMatchMtl
}
});
var response2 = client2.Execute(request2);
if (!response2.IsSuccessful)
{
throw new Exception($"API call to GetAvailableToMatch failed: {response2.Content}");
}
dynamic getAvailableToMatchResponse = JsonConvert.DeserializeObject<dynamic>(response2.Content);
// UpdateSMMtl
var client3 = new RestClient(baseUrl + "UpdateSMMtl");
var request3 = new RestRequest(Method.POST);
request3.AddHeader("Content-Type", "application/json");
request3.AddHeader("Authorization", $"Basic {basicAuth}");
request3.AddHeader("X-API-Key", apiKey);
var availToMatch = ((IEnumerable<dynamic>)getAvailableToMatchResponse.parameters.ds.AvailToMatch).Select(m => new
{
m.Company,
m.PartNum,
m.SerialNumber,
m.JobNum,
m.IssueToAssembly,
m.MtlSeq,
Matched = true, // Match the material serial number
Selected = true, // Select the material serial number
m.AttributeSetID,
m.AttributeSetIDDescription,
m.AttributeSetIDShortDescription,
m.RevisionNum,
m.SysRowID,
RowMod = "U"
});
request3.AddJsonBody(new
{
ipMode = "J",
ds = new
{
AvailToMatch = availToMatch,
SerialMatchAsmbl = getAvailableToMatchResponse.parameters.ds.SerialMatchAsmbl,
SerialMatchHdr = getAvailableToMatchResponse.parameters.ds.SerialMatchHdr,
SerialMatchMtl = getAvailableToMatchResponse.parameters.ds.SerialMatchMtl
}
});
var response3 = client3.Execute(request3);
if (!response3.IsSuccessful)
{
throw new Exception($"API call to UpdateSMMtl failed: {response3.Content}");
}
dynamic updateSMMtlResponse = JsonConvert.DeserializeObject<dynamic>(response3.Content);
// SetFullyMatchedHidden
var client4 = new RestClient(baseUrl + "SetFullyMatchedHidden");
var request4 = new RestRequest(Method.POST);
request4.AddHeader("Content-Type", "application/json");
request4.AddHeader("Authorization", $"Basic {basicAuth}");
request4.AddHeader("X-API-Key", apiKey);
request4.AddJsonBody(new
{
ipAssmblSeq = ipAssemblySeq,
ipHideFullyMatched = false,
ds = updateSMMtlResponse.parameters.ds
});
var response4 = client4.Execute(request4);
if (!response4.IsSuccessful)
{
throw new Exception($"API call to SetFullyMatchedHidden failed: {response4.Content}");
}
dynamic setFullyMatchedHiddenResponse = JsonConvert.DeserializeObject<dynamic>(response4.Content);
// Log the final response
// Ice.Diagnostics.Log.WriteEntry($"SetFullyMatchedHidden Response: {JsonConvert.SerializeObject(setFullyMatchedHiddenResponse)}", System.Diagnostics.EventLogEntryType.Information);
Currently it fails at GetAvailableToMatch with this error.
"API call to GetAvailableToMatch failed: {\"HttpStatus\":400,\"ReasonPhrase\":\"REST API Exception\",\"ErrorMessage\":\"Serial Match Material not available.\",\"ErrorType\":\"Ice.BLException\",\"ErrorDetails\":[{\"Message\":\"Serial Match Material not available.\",\"Type\":\"Error\",\"Table\":\"SerialMatchMtl\",\"Program\":\"Erp.Services.BO.SerialMatching.dll\",\"Method\":\"GetAvailableToMatch\",\"LineNumber\":1563,\"ColumnNumber\":21}],\"CorrelationId\":\"e716d15a-1b43-40f8-affc-04660557a307\"}"
I thought maybe if I used strongly typed classes it would be easier to debug but when I tried, I couldn’t work out how to define the classes. I always got this error.
BPM009 Member declaration is not allowed inside code block
I’ve seen posts stating you can just create and reference a DLL but I don’t think I can do that on cloud. I thought maybe I could put the class declarations in its own function, but I get the same declaration error.
Any tips or advice at all are greatly appreciated. Thanks in advance.