Epicor ERP can you call an Epicor Function within a Customization - customization

Epicor ERP 10.2.500 has been recently released with the addition of Epicor Functions. They can be called from within Method and Data Directives.
Do anybody has been able to do so with a Form Customization within Epicor?

This is possible via a REST call to your function API. In this case, I had a function that sent an email from some inputs.
private void epiButtonC1_Click(object sender, System.EventArgs args)
{
//API Key is included in the query param in this example.
var request = (HttpWebRequest)WebRequest.Create("https://{appserver}/{EpicorInstance}/api/v2/efx/{CompanyID}/{LibraryID}/{functionName}/?api-key={yourAPIKey}");
request.Method = "POST";
//All REST v2 requests also sent with authentication method (Token, Basic)
//This should be Base64 encoded
string username = "userName";
string password = "passWord";
string encoded = System.Convert.ToBase64String(System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(username + ":" + password));
request.Headers.Add("Authorization", "Basic " + encoded);
//Add body to correspond to request signature
request.ContentType = "application/json";
using(var writer = new StreamWriter(request.GetRequestStream()))
 {
    var values = new Dictionary<string, string>;
      {
        {"toEmailAddress", "someEmail#email.com"},
        {"fromEmailAddress","someOtherEmail#email.com"}, 
        {"body","This is the body"},   
{"subject","Hello from Client Code!"}
    };
    string json = JsonConvert.SerializeObject(values);
    writer.Write(json);
}
using (var response = request.GetResponse()) 
using (var reader = new StreamReader(response.GetResponseStream()))
{
  var result = reader.ReadToEnd();
  epiTextBoxC1.Text = result.ToString();
}
}

Haven't done it myself personally, but looking into the first post release notes about it here leads me to believe there is no out of the box solution, yet in this version/initial release.
However I'm sure you could do a HTTP request from within the Epicor customization if you have the REST API enabled in your environment.

If you create your own dll that calls the EpicorFunction you can use it within the customization. Still looking for a way to call them directly.

REST endpoint is the recommended way to perform the function call as pointed out by a-moreng.
If for some reason you cannot use this, you can use a passthrough method to any server-side BO via a customization Adapter. For instance, create an updatable BAQ which you can call from a customization using the DynamicQueryAdapter.
Pick an arbitrary table and field to save the BAQ.
Create three string parameters to store the Function library name, the function name, and a delimited list of parameters.
On the GetList method, create a Base Processing Directive.
Split your delimited parameter list and convert them to the appropriate datatypes.
Use the resulting variables to call your function.
If desired, you can pass return variables into the ttResults of the BAQ

Related

Set signature in outlook e-mail body C++

I have a little problem with my outlook interface.
I'm using <outlook\msoutl.tlh> to create and fill an e-mail item automatically.
But now I want to display my signature too.
I noticed that if I don't set the mail body, the signature is added automatically. But as soon as I want to set the mail body, the signature is not shown. It seems that it will be overwritten. So I tried the following :
string standardText = "Hello Outlook"
string signature = IMailItemPtr->Body;
IMailItemPtr->Body = standardText + signature
So first the signature has to be cached and then appended to the standard text for the body.
But here I noticed that the body is empty until set (which is logical).
But now I wonder where my signature is stored and how I can get it?
Here is the important part of my code:
string standardText = "Hello Outlook"
Outlook::_ApplicationPtr spOutlook(__uuidof(Outlook::Application));
// Get the MAPI namespace
Outlook::_NameSpacePtr pMAPI = spOutlook->GetNamespace("MAPI");
// Initiate a new Outlook-session
pMAPI->Logon("", "", false, true); // Log on by using the default profile or existing session (no dialog box).
// Query the MailItem interface
Outlook::_MailItemPtr IMailItemPtr = spOutlook->CreateItem(Outlook::olMailItem);
IMailItemPtr->Subject = mailSubject;
IMailItemPtr->Body = standardText.c_str();

Rally Web Services API: How do I get the URL link of the user story? (getDetailUrl() method)

Please be patient and Do Not flag this as duplicate: Using the Rally REST API, how can I get the non-API (website) URL for a user story?
I want to be able to generate a link for the user story.
Something like this: https://rally1.rallydev.com/#/-/detail/userstory/*********
As opposed to this: https://rally1.rallydev.com/slm/webservice/v2.0/hierarchicalrequirement/88502329352
The link will be integrated into another application for the managers to see the user story.
I did read about the getDetailUrl() method, but in my case I am creating the user stories by parsing email and linking that to a notification service in Slack.
I am aware of the formattedID and (_ref), but I would have to query for it again, and I am creating batches of userstories through a loop. I need the actual web site link to the user story.
Here is my sample code:
public void CreateUserStory(string workspace, string project, string userstoryName){
//authenticate with Rally
this.EnsureRallyIsAuthenticated();
//DynamicJsonObject for HierarchicalRequirement
DynamicJsonObject toCreate = new DynamicJsonObject();
toCreate[RallyConstant.WorkSpace] = workspace;
toCreate[RallyConstant.Project] = project;
toCreate[RallyConstant.Name] = userstoryName;
try
{
//Create the User Story Here
CreateResult createUserStory = _api.Create(RallyConstant.HierarchicalRequirement, toCreate);
Console.WriteLine("Created Userstory: " + "URL LINK GOES HERE");
}
catch (WebException e)
{
Console.WriteLine(e.Message);
}
}
We don't have a method in the .NET toolkit for doing this, but it's easy to create.
The format is this:
https://rally1.rallydev.com/#/detail/<type>/<objectid>
Just fill in the type (hierarchicalrequirement turns into userstory, but all the others are the same as the wsapi type) and the objectid from the object you just created.
var parameters = new NameValueCollection();
parameters["fetch"] = "FormattedID";
var toCreate = new DynamicJsonObject();
var createResult = restApi.create("hierarchicalrequirement", toCreate, parameters);
var type = Ref.getTypeFromRef(createResult.Reference);
var objectID = Ref.getOidFromRef(createResult.Reference);
var formattedID = createResult.Object["FormattedID"];
And you can specify fetch fields to be returned on the created object so you don't have to re-query for it.

Using Apache HttpComponents for http requests with NTLM authentication

Quick background.
CFHTTP doesn't support Windows NTLM/Authenticate authentication, only basic authentication. I need to make http requests that will have to authenticate against NTLM, so I've ended up rolling my own version of CFHTTP.
I found Terry Ryan's article that uses the apache httpclient version 3.1 to perform digest authentication and have built upon that using version 4.1.2 instead which includes NTLM functionality.
I have a function that will perform a get request and then other functions to handle returning a structure that looks like the cfhttp result set. The changes I made are based on the authentication tutorial example.
public any function httpRequest(url,username,password,domain) {
var httpClient = createObject("java","org.apache.http.impl.client.DefaultHttpClient");
var authScope = createObject("java","org.apache.http.auth.AuthScope");
var httpCredentials = createObject("java","org.apache.http.auth.NTCredentials");
var httpGet = createObject("java","org.apache.http.client.methods.HttpGet");
var jURL = createObject("java", "java.net.URL").init(arguments.url);
var host = jURL.getHost();
var path = jURL.getPath();
var httpHostTarget = createObject("java","org.apache.http.HttpHost").init(host,80,"http");
var localContext = createObject("java","org.apache.http.protocol.BasicHttpContext");
var httpContent = {};
var response = '';
if (len(arguments.username) and len(arguments.password) gt 0){
httpCredentials.init(arguments.Username, arguments.password, cgi.remote_host,arguments.domain);
httpClient.getCredentialsProvider().setCredentials(authScope.ANY, httpCredentials);
}
if (!Len(path)) path = "/";
httpGet.init(path);
response = httpClient.execute(httpHostTarget, httpget, localContext);
httpContent = convertHttpClientResponseToCFHTTPFormat(response);
httpClient.getConnectionManager().shutdown();
return httpContent;
}
This was working fine until I altered the function to perform the authentication.
Unfortunately I'm now getting :
The execute method was not found.
Either there are no methods with the specified method name and argument types or the execute method is overloaded with argument types that ColdFusion cannot decipher reliably. ColdFusion found 2 methods that match the provided arguments. If this is a Java object and you verified that the method exists, use the javacast function to reduce ambiguity.
As far as I can tell there is only one matching execute() function in HttpClient for the object classes passed to it, so I'm a little confused. JavaCast doesn't allow you to cast to complex objects or super types, so that didn't work.
Can anyone suggest how I can get this to work? How can I reduce the ambiguity?
Looking at the error, it's getting confused between two execute methods that have the same number of parameters. Although I don't know why it is...
Anyway, I found a way around the error. It involves pulling the method you're after out of the class and invoking it directly. If ColdFusion was happier with casting Java objects life might be easier.
//response = httpClient.execute(httpHostTarget, httpget, localContext);
classes = [httpHostTarget.getClass(), CreateObject('java', 'org.apache.http.HttpRequest').getClass(), CreateObject('java', 'org.apache.http.protocol.HttpContext').getClass()];
method = httpClient.getClass().getMethod('execute', classes);
params = [httpHostTarget, httpget, localContext];
response = method.invoke(httpClient, params);
There may be another way of doing this (casting instead) but it's all I've got ;)
As a guess, could you be loading the wrong version of the .jars ? You don't seem to be using JavaLoader like Ryan did...

web servise & data binding with WP7

I want to display a list of friends, and when i select a friend my app will navigate to another page showing this informations related to this friend.
I'm trying to read data using web service and display some of it(name and photo) on a costumized lisBox, and store some (id) temporarily in a list or collection that i can call it after and use it in my url:
NavigationService.Navigate(new Uri("/MyApp;component/FriendDetails.xaml?id{0}",friend_id, UriKind.Relative));
Use WebService to query the api and you need to add a "download callback" in that callback use linq to write the result of the query to an observable collection of an object matching the data you want from the result.
like this.
friends = new ObservableCollection<Friend>();
WebClient wc = new WebClient();
wc.OpenReadCompleted += Feed;
wc.OpenReadAsync(new Uri(friendsURL));
}
private void Feed(object Sender, OpenReadCompletedEventArgs e)
{
if (e.Error != null){
return;
}
using (Stream s = e.result){
XDocument doc = XDocument.Load(s);
then use Linq to cycle through the data and add it your observablecollection of friends.

How do I use RegEx to insert into a JSON response?

I'm using JSON for a web application I'm developing. But for various reasons I need to create "objects" that are already defined on the client script based on the JSON response of a service call. For this I would like to use a regex expression in order to insert the "new" statements into the JSON response.
function Customer(cust)
{
this.Name = null;
this.ReferencedBy = null;
this.Address = null;
if (cust != null)
{
this.Name = cust.Name;
this.ReferencedBy = cust.ReferencedBy;
this.Address = cust.Address;
}
}
The JSON response is returned by an ASP.NET AJAX Service and it contains a "__type" member that could be used to determine the object type and insert the "new" statement.
Sample JSON:
{"__type":"Customer", "ReferencedBy":{"__type":"Customer", "Name":"Rita"}, "Name":"Joseph", "Address":"123 {drive}"}
The resulting string would look like this:
new Customer({"ReferencedBy":new Customer({"Name":"Rita"}), "Name":Joseph", "Address":"123 {drive}"})
I got this so far but it doesn't work right with the ReferencedBy member.
match:
({"__type":"Customer",)(.*?})
replace:
new Customer({$2})
Hmmm why don't you try to make a simplier way to do it? e.g.:
var myJSON = {"__type":"Customer", "ReferencedBy":{"__type":"Customer", "Name":"Rita"}, "Name":"Joseph", "Address":"123 {drive}"};
after check the type: myJSON.__type, and if it is customer, then:
new Customer({"ReferencedBy":new Customer({"Name":myJSON.ReferencedBy.Name}), "Name":myJSON.Name, "Address":myJSON.Address });
It is because you already have a defined data structure, it is not neccessary to use regex to match pattern & extract data.