Do you know the In-App Notification feature from Model Driven Apps? This feature can create a notification that targeted a specific User. We also can add action to the notification so the User can also interact with multiple actions (now is limited to just an open URL). In short, this feature is very useful for creating the Approval process. Without further ado, let’s go to my proposed solution! 😎
The Necessary Part
I created the below table for this demonstration purpose:

As you can see, the User will fill in the Approver that needs to approve the request. Then in the status field, there are 3 options which are Draft, Approved, or Rejected.
For the next one, you need to create a Model-Driven App. The reason for it is because we need to turn on the feature from the Settings (in top-left from the App > go to Features tab > enable the In-app notifications option):

After you enable the feature, you will see the bell icon inside the app:

Create Custom API
To update the data from the backend, we also need to create Custom API. Here is my code:
using Microsoft.Xrm.Sdk;
using System;
namespace DemoPlugin
{
public class ApprovalApi : IPlugin
{
public const string InputParameter = "input";
public const string OutputParameter = "output";
public void Execute(IServiceProvider serviceProvider)
{
var pluginExecutionContext = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(
typeof(IOrganizationServiceFactory));
var service = serviceFactory
.CreateOrganizationService(pluginExecutionContext.UserId);
var input = pluginExecutionContext.InputParameters[InputParameter].ToString();
var data = input.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
var entityName = data[0];
var entityId = new Guid(data[1]);
var type = data[2];
var update = new Entity(entityName, entityId)
{
["tmy_status"] = new OptionSetValue(type == "approve" ? 932000001 : 932000002)
};
service.Update(update);
pluginExecutionContext.OutputParameters[OutputParameter] = "Success";
}
}
}
The code is pretty simple. The API will require string input. This string will contain three pieces of information (separated by ‘;‘ character). The entity name, Id, and also action is chosen by the Approver. The next step is just to update the entity with the information collected. For the output, for now, I just send the “Success” string.
Once you did this, we can register the plugin to our Dataverse instance:

After that, we need to create the Custom API. As usual, I created the Custom API from Custom API Manager by David Rivard – XrmToolBox:

Unfortunetely at the time of writing, in-app notification only allows opening a URL (GET method) which limits how we can process this design as simple as possible. But for now, I created another WebResource page that will bridge the action to the API that we created before. The flow will be like this:

So for the HTML, I created with below code:
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous">
<style>
body,html{
height:100%;
}
</style>
<title>Approval - Loading</title>
</head>
<body>
<div class="container h-100">
<div class="row h-100 justify-content-center align-items-center">
<div id="loading">
<div class="spinner-grow" style="width: 3rem; height: 3rem;" role="status">
<span class="sr-only">Loading...</span>
</div>
Please wait..
</div>
<div id="result" class="text-center"></div>
</div>
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" integrity="sha512-+NqPlbbtM1QqiK8ZAo4Yrj2c4lNQoGv8P79DPtKzj++l5jnN39rHA/xsqn8zE9l0uSoxaCdrOgFs6yjyfbBxSg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script>
<script>
function executeApi() {
var searchParams = new URLSearchParams(window.location.search);
var input = searchParams.get('data');
var baseUrl = window.location.origin;
var url = `${baseUrl}/api/data/v9.2/tmy_approvalapi`;
$.ajax({
url: url,
type:'POST',
data: JSON.stringify({input:input}),
contentType: 'application/json',
dataType: 'json'
}).done(function(result) {
$('#loading').hide();
$('#result').html(`<h3>${result.output}</h3>`);
});
}
$(document).ready(function() {
window.setTimeout(function() {
executeApi();
}, 3000);
});
</script>
</body>
</html>
Create the WebResource and use the above code. Once you created the WebResource, you will get the URL that will be use for the Notification action:

Demo
Once everything is set up, then we can run our demonstration. I created the below data and get the record Id:

Then I construct the below Javascript and execute in the Developer Tools > Console:
var systemuserid = "2AD07D50-3A20-ED11-B83B-00224828E219";
var notificationRecord = {
title: "Request Approval",
body: "There is new request need your attention.",
"ownerid@odata.bind": "/systemusers(" + systemuserid + ")",
icontype: 100000000, // info
data: JSON.stringify({
actions: [
{
title: "Approve",
data: {
url: "https://yourcrm.crm.dynamics.com/WebResources/tmy_loading?data=tmy_request;aa5babb8-872b-ed11-9db1-000d3a542d2f;approve",
navigationTarget: "dialog",
}
},
{
title: "Reject",
data: {
url: "https://yourcrm.crm.dynamics.com/WebResources/tmy_loading?data=tmy_request;aa5babb8-872b-ed11-9db1-000d3a542d2f;reject",
navigationTarget: "dialog",
}
}
],
}),
};
Xrm.WebApi.createRecord("appnotification", notificationRecord).then(
function success(result) {
console.log("notification created with multiple actions: " + result.id);
},
function (error) {
console.log(error.message);
// handle error conditions
}
);
Once you execute the Javascript (you can change this creation to the Plugin as well. But for simplicity, I just use this method 😎):

Below is the demo once you select Approve/Reject:

Happy CRM-ing! 😎
Nice use case…
LikeLike
Reblogged this on ECELLORS CRM Blog.
LikeLike