Tuesday, May 7, 2019

Dynamics CRM for IOT - Hello Intelligent Big Data - Connected Field Service

Dynamics have connected with IoT with Azure, enhancing the number of possible real world implementations. Dynamics 365 Field Service is a best avenue to take advantage of IoT technology for industrial benefits. 

With the massive amounts of data available in field service industry collected via IoT devices, D365 Field Service can move forward in taking sound management decisions using real time data. D365 Field Service is the best platform to manage small to large scale service industry requirements.

Field Service under D365 Umbrella
  • To start with Dynamics 365 is a collection of intelligent business applications on a common platform, And from these, Field Service is a very popular application among manufacturing and service industries. It targets in helping organizations to deliver outstanding onsite/offsite services to their  customers. 

 
  • Field service, extends Microsoft Dynamics 365 to provide an end to end solution to manage field agent activities


  • In general field service is all about completing a work order for the customer fulfilling required resources and services.
    So general field service starts when a customer inquire about a service, then it manages the entire service providing process.
  • It does resource management, inventory management, scheduling, mobile agent handling and Analytics etc.



Internet of Things (IoT)

  • Kevin Ashton (researcher in RFID and sensor technology),  is known for coining the term “the Internet of Things” to describe a system where the Internet is connected to the physical world via ubiquitous sensors.
  • Describes IoT as a network of “eyes and ears” for computers: with Internet of Things, computers can sense things for themselves (Keyboard data entry era is over)

  • One of the first examples of an Internet of Things is from the early 1980s, which was a Coca Cola machine, at Melon University. Local programmers have connected it to internet to see if there was a cool drink available, before making the trip to the machine.
  • In the chart you can see how much of IoT devices are proactively used in various industries. And it is expected to have over 267 billion USD worth IoT devices  by 2020.



Field Service and IoT

Field Service is one of the very first industries to use IoT in Commercial use
  • The field service industry has evolved alongside IoT. And it has established interoperability across devices, applications, and platforms.
    • Reduced Costs - Preventing breakdowns and reducing downtime. Efficient Use Of Resources.
    • Best-of-Breed Solutions - IoT encourages businesses to use software applications and hardware devices are specific to their needs.
    • Customer Satisfaction – The ability to take actions even before customer notice it and make a service call. Proactive services.
The challenge, is how to utilize the massive amount of data generated through IoT devices on the field, to improve operations and customer satisfaction.

D365 Traditional Field Service
  • In a traditional field service organization, when customer gets a problem they calls to arrange a service agent to get it fixed. (Ref: https://www.naviworld-asia.com)


D365 Connected Field Service (CFS)
  • Connected Field Service - Detect, troubleshoot, and resolve issues remotely so a technician is dispatched only when necessary. Know about problems and solve them Just-In-Time before customers are affected using IoT Technology.
  • Connected Field Service eliminates the customer concern by attempting to complete self-healing repairs remotely before sending out a technician





  • Organizations can benefit from “just-in-time” preventative maintenance instead of scheduled preventative because Connected Field Service can look at the actual consumption of a part and send out alerts when the part needs to be changed or cleaned. 



CFS Path to Implementation

Basic:
When an anomaly is detected, Field Service automatically creates a work order and dispatches a technician to consider the issue. This level of Connected Field Service takes a proactive approach to improve customer satisfaction by decreasing overall downtime and making repairs before customers become aware of the problem.
Advanced:
When an anomaly is detected, Field Service asks the device to try to fix itself with a single, self healing command. If that command doesn’t work, then Field Service automatically creates a work order and schedules a technician. Organizations experience improved customer satisfaction levels and gain greater productivity because fewer technicians are dispatched when devices can self-heal.
Expert:

At this level, Field Service initiates a multi-step workflow when an anomaly is detected. This attempts to fix the device in as many ways possible without requiring human intervention. This level maximizes customer satisfaction and resource productivity because a technician is only dispatched when all other possibilities are exhausted.


CFS Implementation

There are two offerings you can use to connect IoT-enabled devices into the Field Service solution:
Connected Field Service for Azure IoT Central (SaaS)
Connected Field Service for Azure IoT Hub (PaaS)



Azure IoT Central

Azure IoT Central is a fully managed global IoT SaaS (software-as-a-service) solution that makes it easy to connect, monitor, and manage IoT assets at scale.

Objective:  Connect a Physical Device to IoT Cloud and then Allow Dynamics 365 Field Service to Act        upon the sensor data.
  • Azure IoT Central can send information about device anomalies to Connected FieldService (as an IoT Alert) for diagnosis.
  • Connected Field Service can create cases or work orders triggered from device anomalies.
  • Connected Field Service can schedule technicians for inspection to prevent the downtime incidents.



  • Azure IoT Central enables builders to configure rules and actions. Based on those actions, IoT alerts will be created in Connected Field Service. Also, based on service activities in Connected Field Service, information can be sent back to Azure IoT Central. This is accomplished by using Microsoft Flow, a SaaS offering for automating workflows across applications and services.




Azure IoT Hub

Objective:  Connect a Physical Device to IoT Cloud and then Allow Dynamics 365 Field Service to Act upon the sensor data.
  • IoT Hub is a managed service, hosted in the cloud, that acts as a central message hub for bi-directional communication between your IoT application and the devices it manages.
  • IoT Hub supports multiple messaging patterns to control your devices from the cloud, such as
    • Device-to-cloud Telemetry
    • File Upload From Devices
    • Request-reply Methods
  • IoT Hub gives you a secure communication channel for your devices to send data
  • Built-in message routing functionality gives you flexibility to set up automatic rules-based message fan-out (Use message routing to control where your hub sends device telemetry)
  • Integration from IoT Hub to other Azure services available to build end-to-end solutions
    • Azure Event Grid
    • Azure Logic Apps
    • Azure Machine Learning
    • Azure Stream Analytics





  • IoT Hub can be used to build IoT solutions with reliable and secure communications between millions of IoT devices and a cloud-hosted solution back-endYou can connect virtually any device to IoT Hub.

Below is a step wise guideline for setting IoT Hub for Field Service
    1.  Apps Automatically created in IoT Hub




    2. Add Connected Field Service in D365 CRM Instance Manage

          
       
     3. Connect your IoT device to Internet

    4. Use Logic app in IoT hub to create records (anything you want as output) for IoT feeds



    5. You will get records created in D365 Field Service according to the IoT feeds



    Sunday, March 10, 2019

    Trigger common plugin code (C#.net) for any entity in Dynamics 365 (CRM)

    Hello dynamic world,

    Now this is a simple trick I learnt to do to make my life much easier. The simple case study was that, I wanted to call same function, on create/update of several entities, with some pre-defined conditions for each entity.

    Now I could have write separate handler for each entity (entity01handler, entity02handler, .. , entitynhandler) and call the same function keeping it accessible for all handlers.

    However what I did is write one handler for all the entities. It was just simple as passing null for target entity in step register.

    public class CommonEntityHandler : Plugin
    public CommonEntityHandler() : base(typeof(CommonEntityHandler)) {
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, ContextMessageName.Create, null, new Action<LocalPluginContext>(ExecuteCommonEntityCreate)));
                base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, ContextMessageName.Update, null, new Action<LocalPluginContext>(ExecuteCommonEntityUpdate)));            base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, ContextMessageName.Associate, null, new Action<LocalPluginContext>(ExecuteCommonEntityAssociate)));            base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, ContextMessageName.Disassociate, null, new Action<LocalPluginContext>(ExecuteCommonEntityDisassociate)));            base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PreOperation, ContextMessageName.Disassociate, null, new Action<LocalPluginContext>(ExecuteCommonEntityDisassociate))); }
    private void ExecuteCommonEntityCreate(LocalPluginContext localContext)
     {
       localContext.TracingService.Trace("Common Entity create " + localContext.PluginExecutionContext.Depth);
       if (localContext == null || localContext.OrganizationService == null)
        {
           throw new ArgumentNullException("localContext");
        }
    
        IOrganizationService service = localContext.OrganizationService;
        ITracingService tracingService = localContext.TracingService;
        IPluginExecutionContext context = localContext.PluginExecutionContext;
        tracingService.Trace("start create");
        try
        {
          if (localContext.PluginExecutionContext.InputParameters.Contains(InputParameter.Target) && localContext.PluginExecutionContext.InputParameters[InputParameter.Target] is Entity)
          {
            var commonEntity = localContext.PluginExecutionContext.InputParameters[InputParameter.Target] as Entity;
    
          // use commonEntity.Id, commonEntity.LogicalName, commonEntity.Name for your logic
          }  
        }
        catch (InvalidPluginExecutionException)
        {
            throw;
        }
     }
    }

    Sunday, October 28, 2018

    Dynamics 365 Workflow Scope - User or Organization

    Hello mobile world,

    Now this is something I didn't pay much attention until QA reported a bug. Workflow doesn't get fired when record create is synced using CRM Resco Mobile.

    Workflow scope defines the level of records the workflow will be triggered on. This is something you must pay attention to as  much as the user role security. When you create a workflow in Dynamics 365 V9, by default it's set to User Scope. Workflows with user scope will trigger only for the records that user is privileged to. 


    1. User
    Choosing this scope means the workflow will run only on the records owned by the same user as the workflow user. This is more like a private workflow of the user.
    2. Business Unit
    This means the workflow will run on all records owned by the users of the same business unit as the workflow user. 
    3. Parent: Child Business Unit
    With this, the workflow will run on the records owned by the users of the same business unit as the workflow user as well as any child business units. 
    4. Organization
    The workflow will run on records owned by any user in CRM. Since it will trigger for all records, organization scope is the most used scope option.

    For automatically triggered workflows, they are executed in the security context of the workflow process’s owner and not according to the user who performed the action on the record, that might trigger the workflow (if workflow scope supports).

    No matter which Administrative privileges you have on your CRM User, you won't be able to trigger a workflow set to User Scope and Owned by other user. :P

    And also this scope applies to all the records and logic in the workflow steps too. For example, imagine you triggered the workflow (Scope = user) on Contact record update (which your user owns) and then you are going to update the Primary Account of the Contact. To update, your User should own the relevant Account record too. Otherwise the workflow will give error.

    Now, for the issue I got with CRM Resco Mobile, I had to set the workflow Scope to Organization, to allow it to trigger on Mobile data sync event.

    Hope this will be useful to somebody.

    Wednesday, October 24, 2018

    Dynamics 365 Custom Actions - Bound and Unbound with Xrm.WebApi.online.execute()

    Hello World,

    It all started when I tried to use Xrm.WebApi.online.execute() method to call CRM Custom Action from Custom Web Resource.
    https://docs.microsoft.com/en-gb/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi/online/execute.
    Instead calling the CRM actions by manually making XmlHttpRequests, below seems to be easy to code.

    Xrm.WebApi.online.execute(request).then(successCallback, errorCallback);

    Isn't it obvious to select above instead of below hazzard,

    var req = new XMLHttpRequest();
    req.open("POST", actionUrl, false);
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.onreadystatechange = function () {
    req.setRequestHeader("OData-Version", "4.0");
        if (this.readyState == 4 /* complete */) {
       req.onreadystatechange = null;
            if (this.status == 200 || this.status == 204) {
       // get output
      }
     }
    }

    Xrm.WebApi that came with V9 provides number of methods like, createRecord, deleteRecord, retrieveRecord, retrieveMultipleRecords, updateRecord, execute and executeMultiple. Create/Update and Retrive was quiet easy to use.

    To call custom actions, we can use Xrm.WebApi.online.execute() method, and below is where I got stuck.



    In making the request object, how to specify the bound parameter? First of all what's bound/ unbound action?

    Unbound Action is nothing but, the Global Action, which is not bound to any Entity :D. Therefore Bound Actions are Actions with a specific Entity.

    Now below is an Action bound to Contact Entity.



    Now calling Unbound Actions is easy, just use boundParameter: null


    For Bound Actions, how to specify the BoundParameter?


    To understand how your Action actually takes it's boundParameter and other Input/Output parameters, download the OData Metadata file from Customizations --> Developer Resources. And below is what we get for above sample action.

    <Action Name="msdyn_GDPROptoutContact" IsBound="true">
        <Parameter Name="entity" Type="mscrm.contact" Nullable="false" />
        <Parameter Name="optout" Type="Edm.Boolean" Nullable="false" />
    </Action>

    Now you can see that in-addition to Input/Output parameters, we have a parameter named as "entity". Actually this is documented here in https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/webapi/use-web-api-actions, but we tend to miss it, first time we read.

    So now when making your request object for Xrm.WebApi.online.execute() method, treat "entity" as a parameter.

    For example below is how you should code the request object for above action.

    var target = { entityType: "contact", id: "69DA0233-2D96-W891-B93F-207D7B3BF6C8" }; var reqObject = {}; reqObject.entity = target; reqObject.optout = true; reqObject.getMetadata = function () { return { boundParameter: "entity", operationType: 0, operationName: "msdyn_GDPROptoutContact", parameterTypes: { "entity": { typeName: "mscrm.contact", structuralProperty: 5 }, "optout":{typeName: "Edm.Boolean", structuralProperty: 1} } } };

    For me this is a life saving solution :)

    Thanks for reading this long.

    Sunday, September 23, 2018

    Closer look into Custom Actions - CodedActivity or Plugin Step ?

    Hello Complicated World,

    Actions, which was introduced in 2013 now have been around for a very long time. Action is definitely a process that allows a non developer user to create and add some logic (child steps) same as Workflows. Yet in the hand of a CRM developer Actions can do magics ;) .

    To list down the differences, 
    1. Actions can only be called or triggered by a custom code, a client side (JavaScript call) or a server side code (inside C# plugin or custom workflow) call. 
    2. Actions can support for Global entity, meaning that Actions can stay unbound to any specific entity and serve it's purpose at any time it get's called. 
    3. When calling the action, we can pass input parameters to the actions and retrieve output parameters on the successcallback.

    Now the important questions, what does Custom Actions mean?

    When it comes to  CRM customization, we mainly consider Custom Plugins inherited from IPlugin and Custom Workflows inherited from System.Activities.CodeActivity, where both comes with custom C# dlls to register.

    Custom Actions don't have such code implementations. Custom Actions means simply creating new Actions in CRM in-addition to OOB Actions provided by default.

    Yet there are two ways to extend Actions beyond CRM by triggering custom C# code. The selection is either to, 
    • Use Custom Action name as a SDK Message to trigger a Plugin step
    • Add custom workflow as a step inside Custom Action

    Use Custom Action name as a SDK Message to trigger a Plugin step

    Simple steps to follow are,

    1. Create a new Action Process with input/output parameters and Activate the action



    2. Create a new plugin dll project and write a plugin step handler for the action. I am using SDK plugin class implemented by inheriting IPlugin here. You can directly use IPlugin and use execute method.
    public class testActionHandler : Plugin { public testActionHandler() : base(typeof(testActionHandler)) { base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>((int)PipelineStage.PostOperation, "tst_testAction", "", new Action<LocalPluginContext>(ExecuteAction))); } private void ExecuteAction(LocalPluginContext obj) { var pluginExecutionContext = localContext.PluginExecutionContext; var inputparam = (string)localContext.PluginExecutionContext.InputParameters["inputarg"]; //your custom code pluginExecutionContext.OutputParameters["outputarg"] = true; } }
    3. Register the plugin step inside the custom plugin dll assembly and use Action name as the message name (it should come in the dropdown ;)). 



    Now you are good to go and you can call this action from both JavaScript and other plugins and workflows. So the execution order would be,
    Action call --> Custom Action Trigger --> Plugin step trigger


    Add custom workflow as a step inside Custom Action

    This is almost similar to calling custom workflows inside OOB workflow. 

    1. Write a CodedActivity class and configure it's input parameters. 
    public class testActionHandler : CodeActivity { [Input("inputarg")] public InArgument<string> inputarg { get; set; } [Output("outputarg")] public OutArgument<Boolean> outputarg { get; set; } protected override void Execute(CodeActivityContext executionContext) { ITracingService tracingService = executionContext.GetExtension<ITracingService>(); IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>(); IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>(); IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId); var inputarg = context.InputParameters["inputarg"]; // your code here var output = true; outputarg.Set(executionContext, output); } }
    2. Add a step inside the action and call the registered custom workflow


    And now you are done. :)

    Okay now the important question, what's best way?


    According to my view, best way to extend an Action with C# is to use plugin steps. Reasons behind are, 
    • The Action is independent from the plugin steps we create using it. We can delete the plugin steps without affecting the Action. But when you add a custom workflow (CodedActivity) as a step inside Action, you cannot delete the custom workflow without removing it from the Action first.
    • It's easy to manage input parameters with plugins, rather than with custom workflows. With custom workflows, sometime resetting input parameters become a hazard as it doesn't get update in CRM UI immediately. 

    Adding custom workflow as a step make-sense when you want to re-use an existing workflow. Otherwise you are just increasing dependencies.

    Let me know your thoughts on this. :)

    Tuesday, August 14, 2018

    Microsoft Common Data Service (CDS) V2 for Dynamics 365 CRM and AX - Data Integration - Advance Technical Preview

    Hello World,

    I consider my self lucky as I am getting to experience the new features of the Microsoft CDS V2 (spring update) releases fresh out of their oven, under technical preview for about a year now. It's quite fascinating to see how it grows into a highly capable product gradually.

    Microsoft's original definition of CDS: "The Common Data Service is the Microsoft Azure-based business application platform that enables you to easily build and extend applications with their business data. The Common Data Service does the heavy lifting of bringing together your data from across the Dynamics 365 family of services so you can focus on building and delivering the apps, insights and process automation that matter to you and your customers with PowerApps, Power BI, and Microsoft Flow."

    Now this post is about the data integration between Dynamics 365 (CRM) and Dynamics 365 Finance and Operations (AX) using CDS, as it work for bringing the Dynamics 365 family together. 

    The Data Integration feature is currently available as a tab in the PowerApps Admin Center. Microsoft uses a feature flag to enable Data Integration for technical preview. So we go as, https://preview.admin.powerapps.com/environments?feature.showDataIntegration=true

    The basic setup for integration is as below diagram,



    Prerequisites to use CDS for Data Integration
    • Microsoft Dynamics 365 for Finance and Operations (AX), Enterprise edition July 2017 update with Platform update 8 (App 7.2.11792.56024 w/ Platform 7.0.4565.16212). Support for App 7.1 will be added with a hotfix. Or,
    • Dynamics 365 Sales, Enterprise Edition (CRM). The integration solution is compatible with Microsoft Dynamics 365 Customer Engagement Version 1612 (8.2.1.207) (DB 8.2.1.207) online.

    And, you must also have:

    An environment in the Common Data Service. The environment must have a database for integration and you must be an environment administrator for that database. 

    First thing to setup are the Connections. For that you have to setup Connections for both source and target environments using normal power apps connection tab.



    Then go to the PowerApps Admin Center and create the Connection Set by giving Source and Target Environment Connections.



    Okay now all done to Create a project. Here you can select any template Microsoft has already published with complete data mappings, or you can create your own Custom Template.



    For now Microsoft Templates are available for CRM and AX Sales, FSA and PSA Combinations and I have witnessed it growing for the past few months.

    Sales Integration Map

    To use Microsoft Templates for Sales, you have to add Prospect to Cash Integration Solution (Which is very bulky) into your Dynamics 365 environment. Yet it's not required if you know how to manage data integration with keys. Therefore I went with my custom maps with small configuration changes in CRM side (like just adding a ContactNumber field in CRM to map with AX Contact Number).

    FSA Integration Map

    PSA Integration Map

    Good Documentation of the Data mapping between Dynamics 365 and Dynamics 365 Finance and Operations can be found in https://docs.microsoft.com/en-us/dynamics365/unified-operations/dev-itpro/data-entities/data-integration-cds?toc=/fin-and-ops/toc.json

    Now with the showDataIntegration=true, feature flag the new feature available is the Advance Query option.


    In the Advance Query View you get freedom to use Power Query Language ( M Language) and apply various Filters and Queries for Source Data (Working on this Advance Query section kind of feels like old SSIS, if you know what I mean :) ). Reference to Power Query can be found in https://msdn.microsoft.com/en-us/query-bi/m/power-query-m-reference

    There's more to tell about advance querying. Next post for sure.

    Thanks for reading, if you came this long. :)

    Wednesday, July 4, 2018

    Dynamics 365 (CRM) Get Primary Field name and Primary Id field name of an given entity



    Hello World,

    When you get to a scenario where you are writing a generic logic to be shared in few plugin steps and you are not sure about the entity you will get to process, but you need to know the schema names of primary field and id of the given entity. So pathetic right :)

    Here is my solution. Use metadata.

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Messages;
    using Microsoft.Xrm.Sdk.Metadata;
    using Microsoft.Xrm.Sdk.Query;
    
    
    //Create RetrieveEntityRequest
      RetrieveEntityRequest retrievesEntityRequest = new RetrieveEntityRequest
        {
             EntityFilters = EntityFilters.Entity,
             LogicalName = primaryEntityName
        };
    
    //Execute Request
      RetrieveEntityResponse retrieveEntityResponse = (RetrieveEntityResponse) service.Execute(retrievesEntityRequest);
      var idFieldName = retrieveEntityResponse.EntityMetadata.PrimaryIdAttribute;
    
      var primaryFieldName = retrieveEntityResponse.EntityMetadata.PrimaryNameAttribute;



    Need to discuss about getting entity relationships too. Next post for sure.