Develop an application behaviour for external API call

1. Introduction

After you have completed the Advanced Tutorial, whose result is a functional order management application, this tutorial focus on the usage of application behaviours on the existing Purchase Order Document.

In this example, we’ll be adding an external API that will fetch the current currency values and exchange rates, and we’ll add that valuable decision making information directly into the purchase order process.

As our external API, to get exchange rate and currency values, we are going to use the Exchange Rate API.

2. Prerequisites

This tutorial assumes that you have created a OMNIA tenant, and are logged in as a user with modeling privileges to this tenant.

It is necessary to have completed the steps in the Advanced Tutorial, as this tutorial builds upon it.

3. Application Behaviours

  1. Access your modeling area and create a new Generic Entity, by accessing the Business / Generic Entities menu option, and clicking “Add New”. Set its name as “Currency”, and define it as a root entity

  2. Now let’s create references to your newly created Generic Entity. Go to Business / Agents and select “Company”, and add a new reference attribute:

    • Name: “CompanyCurrency
    • Type: “Generic Entity” > “Currency

      2.1 Repeat the process for the agent “Supplier”:

      • Name: “SupplierCurrency
      • Type: “Generic Entity” > “Currency
  3. Now go to your Purchase Order Document, and add three new attributes:

    • CompanyCurrency:
      • Type: Reference
      • Attribute Type: Generic Entity > “Currency
      • Is read only?: Yes
    • SupplierCurrency
      • Type: Reference
      • Attribute type: Generic Entity > “Currency
      • Is read only?: Yes
    • ExchangeRate - Type: Primitive - Attribute Type: Decimal - Is read only?: Yes 3.1. Edit the Purchase Order form by going to User Interface / Forms and selecting the PurchaseOrderForm. Change the layout of your newly created elements:
    • SupplierName:
      • Row: 2;
      • Column: 9;
      • Size: 4;
    • CompanyCurrency:

      • Row: 4;
      • Column: 1;
      • Size: 2;
    • SupplierCurrency:

      • Row: 4;
      • Column: 2;
      • Size: 2;
    • ExchangeRate:
      • Row: 4;
      • Column: 3;
      • Size: 2;

  4. Now that we have all the elements created, let’s review our Entity Behaviours to fetch the Company and Supplier currencies and retrieve the rate between them.

    4.1. Add a new Action/Change Entity Behaviour:

    • Name: OnChange_Company
    • Action to attribute: Company
    • Code:
    // Code generated by an accelerator (you can change it if you need)
    // The following code invokes the API to retrieve the data of an entity and set the values in the current entity
    if(string.IsNullOrEmpty(this.Company?.ToString()))
        return;
    
    // In order to prevent to invoke the API if the values were sent by the user
    if(
        this._Dto.HasPropertyChanged(nameof(this.CompanyCurrency))
    )
        return;
    
    var httpClient = this._Context.CreateApplicationHttpClient();
    var dataSource = "Default";
    
    var requestResult = httpClient.GetAsync($"Company/{dataSource}/{this.Company}").GetAwaiter().GetResult();
    
    if (!requestResult.IsSuccessStatusCode)
        throw new Exception($"Can't retrieve the entity '{this.Company}'");
    
    
    var entity = requestResult.Content.ReadAsAsync<CompanyDto>().GetAwaiter().GetResult();
    
    this.CompanyCurrency = entity.CompanyCurrency;
    

    4.2. Edit existing GetSupplierName Behaviour (replace existing code with the following):

    
    // Code generated by an accelerator (you can change it if you need)
    // The following code invokes the API to retrieve the data of an entity and set the values in the current entity
    if(string.IsNullOrEmpty(this.Supplier?.ToString()))
        return;
    
    // In order to prevent to invoke the API if the values were sent by the user
    if(
        this._Dto.HasPropertyChanged(nameof(this.SupplierName)) &&
        this._Dto.HasPropertyChanged(nameof(this.SupplierCurrency))
    )
        return;
    
    var httpClient = this._Context.CreateApplicationHttpClient();
    var requestResult = httpClient.GetAsync($"Supplier/Default/{this.Supplier}").GetAwaiter().GetResult();
    
    if (!requestResult.IsSuccessStatusCode)
        throw new Exception($"Can't retrieve the entity '{this.Supplier}'");
    
    var entity = requestResult.Content.ReadAsAsync<SupplierDto>().GetAwaiter().GetResult();
    
    this.SupplierName = entity._name;
    this.SupplierCurrency = entity.SupplierCurrency;
    
    

    4.3. Edit the existing After Change Behaviour and add the following code:

    if(!string.IsNullOrEmpty(this.Company) && !string.IsNullOrEmpty(this.Supplier))
    {
       var rateArgs = new Dictionary<string, object>() {
         { "from", this.CompanyCurrency }, 
         { "to", this.SupplierCurrency }
       };
    
       var result = SystemApplicationBehaviours.GetExchangeRate(rateArgs);
    
       this.ExchangeRate = (decimal)result["Rate"];
    } else {
        this.ExchangeRate = 0;
    }
    
  5. Let’s add our Application Behaviour that will fetch our currency rates from an external API. Go to Business / Application Behaviours and click on “Add new” button. name it “GetExchangeRate”, select System as Data Source and then add the following code:

    var fromCurrency = (args.ContainsKey("from") ? args["from"].ToString() : "").ToUpperInvariant();
    var toCurrency = (args.ContainsKey("to") ? args["to"].ToString() : "").ToUpperInvariant();
    
    if(string.IsNullOrEmpty(fromCurrency) || string.IsNullOrEmpty(toCurrency))
       throw new Exception($"Both currencies must be sended to calculate the rate.");
    
    if(string.Equals(fromCurrency, toCurrency))
       return new Dictionary<string, object>() { { "Rate", 1m } };
    
    HttpClient httpClient = new HttpClient();
    
    var response = httpClient.GetAsync($"http://api.exchangeratesapi.io/v1/latest?base={fromCurrency}&symbols={toCurrency}&access_key=b5d9b28bbd5df2380b1944ad3be46b3d")
        .GetAwaiter()
        .GetResult();
    
    if (!response.IsSuccessStatusCode)
       throw new Exception($"Can't retrieve the rate between {fromCurrency} and {toCurrency}");
    
    var responseData = response.Content.ReadAsAsync<Dictionary<string, object>>().GetAwaiter().GetResult();
    if(!responseData.ContainsKey("rates"))
       throw new Exception($"Can't retrieve the rate between {fromCurrency} and {toCurrency}");
    
    var rate = (responseData["rates"] as JObject)[toCurrency].ToObject<decimal>();
    
    return new Dictionary<string, object>() { { "Rate", rate } };
    
  6. Now open your Application Behaviour, go to “Edit Namespaces” (bottom-left corner), and add two new Namespaces, as follows:

    Namespace 1:

    • Name: NetHttp;
    • Fully Qualified Name: System.Net.Http;

    Namespace 2:

    • Name: NewtonsoftLinq;
    • Fully Qualified Name: Newtonsoft.Json.Linq

  7. Build & Deploy model

  8. Before we check our results, we just need to create two currency instances, that will fetch it’s value automatically. On your application area, access “Currency” (Configurations > Currency) and add two new instances:

    • Code: EUR; Name: Euro;
    • Code: USD; Name: US Dollar;
  9. Now access the “AnalogSoundCompany (Configurations > Company), and select one “Company Currency” from the list. Now repeat the process for your Supplier (Configurations > Supplier) and add the other currency so you can see the functionality in action.

  10. Create a new Purchase Order and select a “Company” and a “Supplier” to verify that the “Rate” is automatically calculated when you change the “Supplier”, and that’s it, your first Application Behaviour is complete!

Our next tutorial is about Data Sources, click here to get started right away.