Develop an application behaviour for external API call

1. Introduction

After you have completed the Beginner 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 Beginner tutorial, as this tutorial builds upon it.

3. Application Behaviours

  1. Access your modeling area and create a new Generic Entity, by accessing the “Generic Entities” tab, and clicking “Add New”. Set it’s name as “Currency”, and define it as a root entity

    Create_New_GenEntity_Currency

  2. Now let’s create references to your newly created Generic Entity. Go to “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. Go to the “User Interface” tab and change the layout of your newly created elements:

    • CompanyCurrency:
      • Row: 4;
      • Column: 1;
      • Size: 2;
    • SupplierCurrency:
      • Row: 4;
      • Column: 2;
      • Size: 2;
    • ExchangeRate:
      • Row: 4;
      • Column: 3;
      • Size: 2;

    PurchaseOrderDocumentLayout

  4. Now that have all the elements created, let’s add one new Action/Change Entity Behaviour and edit the pre-existing “GetSupplierName” behaviour, so that they’ll fetch the currency value and add the rate calculation as an After Change Entity Behaviour:

    Add new 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 requestResult = httpClient.GetAsync($"Company/Default/{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; 
    

    Edit exinting Behaviour

    • Name: GetSupplierName
    • Action to attribute: Supplier
    • 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.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.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.SupplierCurrency = entity.SupplierCurrency; 
            
    
  • Name: AfterChangeBehaviour
    • 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;
      }
    
  1. Let’s add our Application Behaviour that will fetch our currency rates from an external API. Go to “Extensibility > Application Behaviours” and “Add new”, 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($"https://api.exchangeratesapi.io/latest?base={fromCurrency}&symbols={toCurrency}")
         .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 } };
    
  2. 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

    App_Behaviour_Namespaces

  3. Build & Deploy model

  4. 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;
  5. 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.

  6. 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!

AppBehaviourFinalResult

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