Approval Authorization Process + Power Automate(MS FLOW) + Azure Function

Approval Authorization Architecture Flow

Architecture flow

As we all know our client always surprise us with the tricky and interesting requirements.
While working for one of my client, I mate with this interesting requirement, and a client wanted Approval process for a case entity if money is involving in that, meaning if case is related to refund then based on refund amount case should be assigned to respective team for approval.
As this is quite a straight foreword requirement, we can write one simple workflow or plugin to assign a case to the respective team. 
But the tricky thing is, they want it as configurable and like global service.
When I say configurable, it means a client wants full control on this service and they want themselves to set up all routing rule for approval.

In my scenario, the client wants to run this service on Case entity. Case have to assign the respective team based on Country, Currency and refund Amount. 
Below are some configuration records, as you can see if max amount is 100 EUR then this case should Auto approved without any user interaction, and if case Amount is between 100 to 250, Team lead could be approved it. As client co-worker can add multiple rule base on country currency and Amount. 

Configuration records

Once the case is created in Dynamics 365, co-works (Team Leads, Managers, Sr.Managers) need to approve the case for Refund.

As to make it automated we implemented the Approval authorization process, to implement this we used Azure Function (This will work as Global service and can be work on any entity), plus we used Power Automate (MS FLOW).

As per diagram when the case is get created in Dynamics CRM, MS Flow will get a trigger and it will call Azure function with some parameters, based on refund Amount, country and Currency it search configuration record in “Approval Authorization” entity. In this entity we are maintaining the Approval team and Authorization level. Based on this Case will Auto-assign to the respective team.

Azure function code:

//Azure function which except three-parameter, Country, Currency and amount.

// and output parameter are Assignee team, Authentication level and error message (in case any configuration record not found for any criteria)

using System;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Microsoft.Xrm.Sdk;
using System.Configuration;
using Microsoft.Xrm.Sdk.Query;
using System.Collections.Generic;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System.Net.Http;
using System.Net.Http.Headers;
namespace Approval_Authorization_Service
{
    public static class ApprovalAuthorization
    {
       public static IOrganizationService service;
          [FunctionName("ApprovalAuthorization")]
        public static async Task<IActionResult> Run(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
            ILogger log)
        {
            log.LogInformation("C# HTTP trigger function processed a request.");

            string Country = req.Query["country"];
            string Currency = req.Query["currency"];
            string Amount = req.Query["amount"];

            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();
            dynamic data = JsonConvert.DeserializeObject(requestBody);
            Country = Country ?? data?.country;
            Currency = Currency ?? data?.currency;
            Amount = Amount ?? data?.amount;
            log.LogInformation(Country +" "+ Currency+" "+ Amount);


            if (Country!=string.Empty && Currency != string.Empty && Amount != string.Empty)
            {
                string token = GetCRMToken();

                AuthResponse response = Authentication(Country, Currency, Amount,token);

                if (response!=null)
                {
                    return (ActionResult)new OkObjectResult(new
                    {
                        message = "",
                        ApprovelLevel = response.value[0]._authorizationlevel,
                        assignteam = response.value[0].__assigntoteam_value
                    });
                }
                else
                {
                 string ErrorMesage=   getErrorMessage(Country, Currency, Amount, token);

                    return (ActionResult)new OkObjectResult(new
                    {
                        message = ErrorMesage,
                        ApprovelLevel = string.Empty,
                        assignteam = string.Empty
                    });
                }
            }
            else
            {
                return new BadRequestObjectResult("Please pass a Country on the query string or in the request body");
            }
        }
//////

//Business Logic
   public static AuthResponse Authentication(string Country,string Currency ,string Ammount, string token)
        {
           
            try
            {
                HttpResponseMessage servicerequest = null;
                var client = new HttpClient();
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                var url = Environment.GetEnvironmentVariable("MSCRMORG")+ "/api/data/v9.1/_approvalauthorizations?$select=__assigntoteam_value,_authorizationlevel,__country_value,_maxamount,_minamount,_name,_ranking&$filter=_maxamount ge " + Ammount + " and  _minamount le "+ Ammount + " and  __country_value eq {"+Country +"} and  _transactioncurrencyid_value eq {"+Currency + "}&$orderby=_ranking asc";
                servicerequest = client.GetAsync(url).Result;

                string response = servicerequest.Content.ReadAsStringAsync().Result;
           
                AuthResponse ExitingCRMOrders = JsonConvert.DeserializeObject<AuthResponse>(response);
                if(ExitingCRMOrders.value.Count > 0)
                { return ExitingCRMOrders; }
                else
                {
                   
                    return null;
                }
                
            }
            catch (Exception ex)
            { throw new InvalidPluginExecutionException(ex.ToString()); }
        }
 public static string GetCRMToken()
        {
            try
            {
                var aadInstance = Environment.GetEnvironmentVariable("aadInstance");
                var organizationUrl = Environment.GetEnvironmentVariable("MSCRMORG");
                var tenantId = Environment.GetEnvironmentVariable("CRMTokentenantId");
                var applicationId = Environment.GetEnvironmentVariable("CRMTokenApplicationId");
                var key = Environment.GetEnvironmentVariable("CRMTokenKey");
                ClientCredential clientcred = new ClientCredential(applicationId, key);
                var authenticationContext = new AuthenticationContext(aadInstance + tenantId);
                var authenticationResult = authenticationContext.AcquireTokenAsync(organizationUrl, clientcred);
                var requestedToken = authenticationResult.Result.AccessToken;

                
                return requestedToken;

            }
            catch (Exception ex)
            {
                throw ex;

            }
        }
}
}

MS FLOW:

Click on below link to access flow portal,

https://flow.microsoft.com/

  • Now we will create MS Flow on create of a case that will call Azure function with parameters.
  • Now we can add some null conditions here.
  • Now choose new Http action as below,
  • Call azure function with passing parameters in request body, as you can see below I am passing amount, currency and country dynamically.
  • After http call we have to parse output Json as below, you can pass expected json in Schema.
  • Once we get out put json then we can update case records with those value, to update crm entity record chose new action update a record as below,
  • Now in Update case we have to set record identifier, so flow can understand which record do we need to update.
  • After that, we can set values in other fields as below, here we are getting output values from azure function and those value we are assigning to field By using below function we can set value in respective fields

body(‘AuthService’)[‘assignteam’]

  • Once you setup your flow you can test the flow and can see input and output values.

Here it is, now go ahead and create your own MS Flow and Azure function which will communicate to Dynamics CRM.

Happy Coding 🙂

One thought on “Approval Authorization Process + Power Automate(MS FLOW) + Azure Function

Leave a comment

Design a site like this with WordPress.com
Get started