Create, Configure and Use new User in Dynamics 365 Online

In this article, I will take you step by step to create, configure a new user in Dynamics 365 and fixing of issues which I faced on login with that user.

At first step, go to this link and login with your admin user for your trial environment. 

https://admin.microsoft.com/Adminportal/Home?source=applauncher#/users

You will land up to the page as shown in this screenshot. Click on the “Add a user” button to create a new user.

Fill in the form with your desired user details in the first step of the wizard

At next stage, select a country from the dropdown “Select location”, and check the checkbox to assign a product license to the user as shown below

At next step, you can assign optional settings to the user if you need

At the last step just click the button “Finish adding”

Before closing the window just copy the email address of the newly created user and the password as shown in the screenshot below. You will need these credentials to login into CRM with the created user later on. After copying, just click the “Close” button.

Now in the same browser, open a new Tab and login with the admin user at PowerApps admin center using this link

https://admin.powerapps.com/

After login, under Environments, click on the environment record to open your trial environment

Then in the next window, click on the link “See all” under Users as shown in the below screenshot

Next, click on the “Add user” ribbon button at the top, a popup in the right-side panel will appear, just enter the email address of newly (created user in previous steps) and click the “Add” button from the popup window.

A popup appears then. Just click “Not Now” at this point.

Now just open the settings area of CRM by clicking on “Advanced Settings” using a gear icon at the top right corner as shown below

Now go to Settings -> Security -> Users Then select the view “Enabled Users” from the view’s dropdown at the top left corner. You will see the newly created user in the enabled users’ list.

Next, you will need to login into CRM with the newly created user. For that, we just need to verify if proper roles are assigned to the user or not. Just open the user record as shown in the screenshot above. Then on the next screen, click on the ribbon button “MANAGE ROLES”, and scroll down to see if any default security role is assigned to the user record or not. You will see a role named “Sales, Enterprise app access” will be automatically assigned to the user record. Here you can assign other roles also for the user record and you can remove the current role also. But, in order to use a user in CRM, you need to assign at least one role to a user record.

Now do a test to verify if you can log in successfully with the created user without any issue. Just use your environment URL, Email address, and password which you copied in previous steps

https://mytrainingsolutions1.crm5.dynamics.com/main.aspx

Then you might see a popup to change your password on first time login

In order to proceed with a successful login, after changing the password, in the next window, you will see options as shown in this screenshot. I will opt to choose “Skip for now (14 days until this is required)” as I am using a trial environment. You can click this skip option for the next 14 days. After that, you will need to configure two-factor authentication to login into Dynamics 365 CRM using the “Microsoft Authenticator” app from Play Store from your mobile set. This configuration, we will see in another blog.

In the next step, you might see an issue that CRM can complain about the security role assigned to the user. As shown below

So, I went to the user records again, and assigned a default security role on the user record, and closed the above login window which is showing an error, and opened a new private window using IE, and tried login again. At this time, I was successfully logged into the CRM.

That’s it!

Use CRM Web API in C# in Dynamics 365 using Azure Authentication

Login to Azure Portal using URL http://portal.azure.com/

Use Credentials for your Dynamics 365 Account and you will land on the page like this. Click the Azure service icon “Azure Active Directory” here.

Then click on “App registration” option from left panel

Then on next screen, if you do not have any app registered here already then click “New Registration” option, otherwise click on link of your App under “Owned applications”, shown in this screenshot as 1 and 2, respectively.

When you clicked “New registration”, following screen will be in front of you and just fill this and hit the “Register” button.

Now your App is registered successfully and some useful IDs are created which we will use in a C# console application to perform Azure AD Authentication to get access token which will be used to retrieve data from CRM application. Next, click on “Certificates and secrets” option from left panel to generate Client Secret.

In next page you need to click on “New client secret” option

Then a record for client secret will be created successfully. You need to just copy the generated client secret and save that in some notepad to use that in C# console application for retrieval of data from CRM.

Now just go to home page in your Azure portal and copy the Tenant ID as shown in this screenshot

Now you have four things which are needed to authenticate your CRM Web API requests using Azure AD in C# i.e.

  1. ClientId
  2. ClientSecret
  3. TenantId
  4. CRM environment base URL

Next, you can see a C# code snippet to get Access token using OAuth2 from Azure AD of your Dynamics 365.

Complete code with an API call and Access token is given below. Please note that the code has dummy ClientId, ClientSecret, TenantId and CRM environment base URL. Please create these IDs with your own Dynamics 365 credentials and this C# code will work without any issue.

using System;
using System.Net;
using System.Net.Http;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Threading.Tasks;
using System.Net.Http.Headers;
using Microsoft.IdentityModel.Clients.ActiveDirectory;

namespace CRMConnectAzure
{
    class Program
    {
        private const string ClientId = "7a58c565-6748-42a2-5555-abcd9f2e18e3";
        
        //Azure Application Client Key / Secret
        private const string ClientSecret = "m.99KxU-PBh-S4NEUBnNbaRRat.MG7_n04";

        private const string TenantId = "7ffd1e73-c19f-8685-b4cf-46302a8fca78";

        //Resource / CRM Url
        private const string CrmURL = "https://mytechsolutions1.crm4.dynamics.com";

        //Guid is your Azure Active Directory Tenant Id
        
        private const string Authority = "https://login.microsoftonline.com/"+ TenantId +"/oauth2/token";

        private static AuthenticationResult _authResult;

        static void Main(string[] args)
        {
            AuthenticationContext authContext = new AuthenticationContext(Authority);
            ClientCredential credentials = new ClientCredential(ClientId, ClientSecret);
            _authResult = authContext.AcquireToken(CrmURL, credentials);
            Task.WaitAll(Task.Run(async () => await GetAccounts()));
            Console.ReadLine();
        }

        private static async Task GetAccounts()
        {
            using (HttpClient httpClient = new HttpClient())
            {
                httpClient.BaseAddress = new Uri(CrmURL);
                httpClient.Timeout = new TimeSpan(0, 2, 0);
                httpClient.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
                httpClient.DefaultRequestHeaders.Add("OData-Version", "4.0");
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", _authResult.AccessToken);
                //Add this line for TLS complaience
                ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
                var retrieveResponseTest = httpClient.GetAsync("/api/data/v9.1/accounts?$select=accountid,name,_primarycontactid_value&$filter=name ne null&$top=15").Result;
                if (retrieveResponseTest.IsSuccessStatusCode)
                {
                    var jRetrieveResponse = JObject.Parse(retrieveResponseTest.Content.ReadAsStringAsync().Result);
                    dynamic collAccounts = JsonConvert.DeserializeObject(jRetrieveResponse.ToString());
                    foreach (var data in collAccounts.value)
                    {
                        Console.WriteLine("Account Name – " + data.name.Value + " - Guid: " + data.accountid.Value);
                    }
                }
                else
                {
                    return;
                }                    
            }
        }
    }
}

Thats it!

Dynamics 365 CRM – Add HTML WebResources as Sub Area in Sitemap

In daily routine, while working in CRM, we keep using entities from the sitemap.

In this article, I am going to show you how we can add HTML web resources in Sitemap as Sub Area. An HTML page can be accessed in the same way as we access any entity in CRM.

There are different blogs that are available over the internet which shows how to do this using C# code.

The major challenge was to add HTML web resource in Sitemap and then publish using JavaScript code only.

I am using the “Settings” area and “Extensions” group in the XML of sitemap where I will add a subarea representing an HTML web resource. You can choose any area and group from a sitemap as per your needs.

The code below has 4 JS functions

createHTMLSubArea //— used to call “createHTMLSubArea”

addSitemapSubArea //— Used to add HTML webresource in sitemap

updateAndPublishSitemap //— Used to update sitemap XML after adding a webresource

publishSitemap //— Called from within function “updateAndPublishSitemap”. This will just publish the updated sitemap.

I tried to find a way over the internet how to publish sitemap changes using JavaScript but I didn’t find any blog depicting that. In order to think about its solution, I thought there should be some way to do this in RestBuilder (Developer by Jason Latimer). There is an action named “PublishXml” in RestBuilder. So, I used this and it worked. You can use PublishXmlRequest in C# to achieve the same. This is the link to Rest Builder.

RestBuilder

Here is the complete code in JavaScript

// JavaScript source code
var Sitemap = Sitemap || {};

Sitemap.createHTMLSubArea = function()
{
    var webResourceGuid = '0e0207a0-68d5-46a7-92fd-d5901aea8428'; //-- A unique GUID of a web resource in CRM
    var InputParam_subAreaId = 'AUniqueSubAreadId'; //--- Any text containing alphabets and under score without space
    var InputParam_subAreaURL = '$webresource:prefix_ASampleHTMLPage'; //-- An HTML page already registered in CRM as a web resource
    var InputParam_subAreaTitle = 'A Sample HTML Page'; //--Any text containing alphabets and spaces
    var InputParam_subAreaIcon = '$webresource:prefix_/Images/Common/AnyImage32'; //--- It can be JPG, GIF or PNG
    var subAreaDescription = '';
    Sitemap.addSitemapSubArea(webResourceGuid, InputParam_subAreaId, InputParam_subAreaURL, InputParam_subAreaTitle, InputParam_subAreaIcon, subAreaDescription);
}

Sitemap.addSitemapSubArea = function (webResourceGuid, InputParam_subAreaId, InputParam_subAreaURL, InputParam_subAreaTitle, InputParam_subAreaIcon, subAreaDescription) {
    var InputParam_GroupId = "Extensions";
    var inputParam_AreaId = "Settings";
    var req = new XMLHttpRequest();
    req.open("GET", Xrm.Page.context.getClientUrl() + "/api/data/v8.1/sitemaps?$select=sitemapid,sitemapxml", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.send();

    if (req.readyState === 4) {
        req.onreadystatechange = null;
        if (req.status === 200) {
            var data = JSON.parse(req.response);

            if (data != undefined && data != null) {
                var sitemapXML = data.value[0]["sitemapxml"];
                var sitemapId = data.value[0]["sitemapid"];
                var oParser = new DOMParser();
                var oDOM = oParser.parseFromString(sitemapXML, "application/xml");
                var areas = oDOM.children[0].getElementsByTagName("Area");
                for (var i = 0; i < areas.length; i++) {
                    var areaId = areas[i].getAttribute("Id");
                    var groups = areas[i].getElementsByTagName("Group");

                    var groupObject = null;
                    for (var j = 0; j < groups.length; j++) {
                        var groupId = groups[j].getAttribute("Id");
                        if (groupId == InputParam_GroupId && inputParam_AreaId == areaId) {

                            var subArea = oDOM.createElement("SubArea");
                            subArea.setAttribute("Id", InputParam_subAreaId);
                            subArea.setAttribute("Url", InputParam_subAreaURL);
                            subArea.setAttribute("Description", subAreaDescription);
                            subArea.setAttribute("Title", InputParam_subAreaTitle);
                            subArea.setAttribute("AvailableOffline", "false");
                            subArea.setAttribute("PassParams", "false");

                            if (InputParam_subAreaIcon != undefined && InputParam_subAreaIcon != null && InputParam_subAreaIcon != '') {
                                subArea.setAttribute("Icon", InputParam_subAreaIcon);
                            }

                            groups[j].appendChild(subArea);
                            break;
                        }
                    }
                }
                Sitemap.updateAndPublishSitemap(oDOM.children[0].outerHTML, sitemapId, "add", InputParam_subAreaURL);
            }
        }
    }
}

Sitemap.updateAndPublishSitemap = function (siteMapXML, sitemapId, operationPerformed, webResourceURL) {
    var entity = {};
    entity.sitemapxml = siteMapXML;

    var req = new XMLHttpRequest();
    req.open("PATCH", Xrm.Page.context.getClientUrl() + "/api/data/v8.1/sitemaps(" + sitemapId + ")", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.setRequestHeader("Prefer", "odata.include-annotations=\"*\"");
    req.send(JSON.stringify(entity));

    if (req.readyState === 4) {
        req.onreadystatechange = null;
        if (req.status === 204) {
            Sitemap.publishSitemap(sitemapId, operationPerformed, webResourceURL);
        } else {
            alert('Unable to update sitemap.');
        }
    }
}

Sitemap.publishSitemap = function (sitemapId, operationPerformed, webResourceURL) {
    var parameters = {};
    parameters.ParameterXml = "<importexportxml><sitemaps><sitemap>" + sitemapId + "</sitemap></sitemaps></importexportxml>";

    var req = new XMLHttpRequest();
    req.open("POST", Xrm.Page.context.getClientUrl() + "/api/data/v8.1/PublishXml", false);
    req.setRequestHeader("OData-MaxVersion", "4.0");
    req.setRequestHeader("OData-Version", "4.0");
    req.setRequestHeader("Accept", "application/json");
    req.setRequestHeader("Content-Type", "application/json; charset=utf-8");
    req.send(JSON.stringify(parameters));

    if (req.readyState === 4) {
        req.onreadystatechange = null;
        if (req.status === 204) {
            alert('Sitemap is published successfully.');
        } else {
            alert('Unable to publish sitemap.');
        }
    }
}

Dynamics 365: Get Display Text of TimeZone field in C#

In one of our routine tasks, we received a requirement to retrieve TimeZone display text from the selected option of a whole number field in C# code. So, here I will give detail on how the code is used to retrieve that.

Note that this field is not like common option set field as we usually use in dynamics CRM/365.

The field schema looks like this

1.png

The field displays as shown here

2

We have to pass the selected value of “Time Zone” field which a numeric code value like “1,2,3…”. The following code will return the display text of that time zone as you can see in the above screenshot. You can skip the call to “GetCRMConnectionOnline” method if you are gonna use this code in the plugin then use the organization service object from plugin context instead of creating a new object for connection.

Here is the code which we used to retrieve that

public static void GetTimeZone(int crmTimeZoneCode)
        {
            IOrganizationService service = GetCRMConnectionOnline();
            var qe = new QueryExpression("timezonedefinition"); //-- "timezonedefinition" is the entity name
            qe.ColumnSet = new ColumnSet("userinterfacename"); //--"userinterfacename" is the field name you need to retrieve
            qe.Criteria.AddCondition("timezonecode", ConditionOperator.Equal, crmTimeZoneCode);

            Entity ent = service.RetrieveMultiple(qe).Entities.First();
            string timeZoneText = ent.GetAttributeValue<string>("userinterfacename");
            Console.WriteLine("Time Zone Code = " + crmTimeZoneCode.ToString() + "  **********  Time Zone Option Display Text : " + timeZoneText);
        }

        public static IOrganizationService GetCRMConnectionOnline()
        {
            ClientCredentials clientCredentials = new ClientCredentials();
            clientCredentials.UserName.UserName = "MyUser@XYZ.onmicrosoft.com";
            clientCredentials.UserName.Password = "Passw@rd";

            // For Dynamics 365 Customer Engagement V9.X, set Security Protocol as TLS12
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            // Get the URL from CRM, Navigate to Settings -> Customizations -> Developer Resources
            // Copy and Paste Organization Service Endpoint Address URL 
            string organizationServiceURL = "https://orgName.api.crm4.dynamics.com/XRMServices/2011/Organization.svc";
            IOrganizationService organizationService = (IOrganizationService)new OrganizationServiceProxy(new Uri(organizationServiceURL), null, clientCredentials, null);
            return organizationService;
        }

Moving to Unified Interface

In this article, I am going to explain how you can enable Unified Interface in your Dynamics 365 environment. Besides that, I will also give other useful tips at the end of this article. There are two main options to enable Unified Interface in Dynamics 365 which are given below:-

Enable Unified Interface Only

Unified interface is based on model-driven apps. These apps help admins and developers to rationalize data and functionality as per user needs.

In order to achieve superior performance and usability, all the model-driven apps including those created for legacy web client runs in Unified Interface all the time when enabled “Unified Interface only” mode. What are model-driven apps, will be described later in this article.

As per Microsoft “Environments created before the scheduled release dates will not get this change automatically. Version 9.1.0.3448 onwards, administrators will have the option to change the environment settings to get the Unified Interface Only experience. It is recommended to switch to this mode by following the steps at How to enable Unified Interface Only.

For existing environments, it’s recommended that you:

Read What experiences are available in Unified Interface Only and understand how it affects end-users in your environment.

Test the changes in your Trial or Sandbox environments before applying to your production environment.

Enable the hybrid Interface

When you enable the hybrid interface, core functionalities of sales and customer service will become available by using Unified Interface. Some common features of old legacy web client will not be available in Unified Interface which can be made available in hybrid experience. The names of those common features are given below:-

  • Advanced Find
  • Bulk edit
  • Merge records
  • Record sharing
  • Audit History

Follow these steps to enable hybrid experience

  • In the CRM, Go to Settings -> Administration -> System Settings
  • Select the General tab
  • Select “Yes” against the option “Enable embedding of certain legacy dialogs in Unified Interface browser client”.
  • Then press the OK button.

1.png

After enabling hybrid experience, you will see options (i.e. Edit, Merge, and Share) in CRM entities records. For example, you can see these options on Contact records

2.png

When you disable the option “Enable embedding of certain legacy dialogs in Unified Interface browser client” by selecting “No”, the options (i.e. Edit, Merge and Share) on CRM entities records will no longer be seen.

3.png

4.png

Model-driven Apps

Model-driven apps are component-focused which don’t require any custom coding to develop. Unlike canvas apps, where the designer has complete control over the design of the app, model-driven apps’ layout is based on the components you add in the app. Model-driven apps have the following main benefits

  • Component-based without any need of coding.
  • Unified Interface across a range of devices from desktop to mobile.
  • Design is fully compatible with the latest Dynamics 365 Customer Engagement.
  • You can distribute apps as a solution to use in other applications.

Convert Old Web Client based Apps to Unified Interface

Follow this blog: https://community.dynamics.com/365/b/dynamics365andazuresolutions/archive/2019/02/25/d365-v9-x-how-to-switch-old-web-app-to-unified-interface-using-model-driven-app-settings

 A useful tip: If you want to see your existing dynamics 365 environments with old legacy web client interface, where you have enabled Unified Interface or Hybrid experience, use the query string parameter “forceClassic=1”. See the following screenshot how to use.

5.png

References:

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/enable-unified-inerface-only#how-to-enable-unified-interface-only-mode

https://docs.microsoft.com/en-us/powerapps/maker/model-driven-apps/model-driven-app-overview

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/enable-hybrid-experience 

Dynamics 365: Unified Interface Introduction

Unified Interface was introduced with the release of Dynamics 365 Customer Engagement apps (V9.0) which is focused on consistent user experience across all types of screen sizes (i.e. Web Client, Phone, Tablet, etc.). User will be able to see a similar look and feel on all screens regardless of the device he/she is using.

Some of those capabilities available in Unified Interface include:

  • Similar form experiences to update and view your records. User can move core record types to Unified interface (i.e. Accounts, Contacts, Leads, Opportunities, Activities, and Cases).
  • Interactive dashboards across all devices to view data in a better way.
  • Reference Panel for all entities supported in Unified Interface. Reference Panels can render Sub grids in one section through the Unified Interface (UCI). This is a very nice feature for better user experience to have all sub-grids in one section.
  • Support of right-to-left (RTL) languages.
  • Accessibility improvements with all experiences on Unified Interface.
  • Timeline control helps to communicate with your team about communication with customer on a single page.
  • Business process flows enhanced by docking a stage on your BPF which helps to complete complex steps in the stage.
  • New navigation features are helpful not only to navigate between apps but also to recently viewed records and pinned favorites.
  • Reflowing the components on the screen (responsive nature of the design adapts on any screen size).

Capabilities not yet on Unified Interface

Most of the core functionalities of sales and customer service have moved to the Unified Interface experience. Some of the features that are not yet on Unified Interface can be enabled for display as legacy dialogs in the Unified Interface through the hybrid experience:

  • Custom styling of advanced chart properties (excluding colors and basic formatting)
  • Composite address control
  • Global notifications
  • Admin experiences
  • Editable grids on phones
  • Learning Path

You want to enable the above features in Unified Interface? Click on this link

As per Microsoft documentation: These capabilities will continue to be unavailable in the Unified Interface and Microsoft is working to provide these in future releases.

Read-only entities on Unified Interface

The following are the entities that are currently read-only in Unified Interface:

  • Connection Role
  • KnowledgeArticleViews
  • KnowledgeBaseRecord
  • SharePointDocument
  • SharePointSite
  • SLA
  • SLAKPIInstance
  • Template
  • Contract
  • Contract Lines
  • Contract Templates
  • Case Resolution
  • Service

Reference Links: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/about-unified-interface

Dynamics 365: Facing a notification error message in Trial Dynamics 365 CE i.e. “You are using apps designed for the legacy web client. For best results,…”

After Creation of new trial version of 365 CE, I have seen a message on the app home page

“You are using apps designed for the legacy web client. For best results, update your apps to Unified Interface.”

1.png

Similar notification will be visible to System Administrators whenever they use an app designed for the legacy web client, as shown below:

“This app is designed for the legacy web client and might have features or customizations that aren’t supported in Unified Interface. For best results, update it to Unified Interface.”

2.png

The following are recommended ways to update the apps to Unified Interface based on how the apps were installed in the environment.

Apps created in your Sandbox environment

  • Be sure to import the changes in your target environment via a managed solution only. See Import, update, and export solutions for guidance on installing an update to an existing managed solution.
  • Modify the app properties by following the steps detailed in Manage app properties, and set the Client type to Unified Interface
  • Import the changes to your target environment via a managed solution update.

Apps installed from AppSource

  • Contact the app publisher and get a new version that updates the apps to Unified Interface.

Apps obtained from an ISV or any other third party publisher

  • Contact the ISV (Independent Software Vendor) or the third-party app publisher and get a new version that updates the apps to Unified Interface.

In my case, as I created a brand new trial environment, the solution gets resolved by following this link

https://docs.microsoft.com/en-us/powerapps/maker/model-driven-apps/manage-app-properties

Reference Links:

https://docs.microsoft.com/en-us/dynamics365/customer-engagement/admin/update-apps-to-unified-interface

https://docs.microsoft.com/en-us/powerapps/maker/model-driven-apps/manage-app-properties

CRUD Operations Using Xrm.WebApi in Dynamics 365 V9.x

In this article, I will show sample code in JavaScript to create, update, delete, retrieve single and retrieve multiple records using Xrm.WebApi. There are two ways to use this web API i.e. Xrm.WebApi.online and Xrm.WebApi.offline. The “online” mode is used when connected to Customer Engagement server in online mode to execute Web API actions and functions. Whereas, offline is for Dynamics 365 for Customer Engagement mobile clients while working in the offline mode.

I have created JS functions with names createRecord, updateRecord, retrieveRecord, deleteRecord, and retrieveMultiple and these will be executed in the same order by calling one after the other completes its execution. As Xrm.WebApi executes in Asynchronous way. So, I am calling each function from inside other functions automatically, starting from one main function i.e. executeCRUDOperationsByWebAPI;

From the function “executeCRUDOperationsByWebAPI”, I am calling “createRecord”. As soon as the function “createRecord” completes its execution, it will call “updateRecord” automatically. Similarly, the function “updateRecord” will call “retrieveRecord” after it completes its execution. Then “deleteRecord” will be called and at the end “retrieveMultiple” executes.

I am showing a code of the first two functions here to keep this article short. The complete code for all CRUD operations can be downloaded from GitHub location from this link. The code file name in this code repository is “WebAPI_CRUD.js”.

function createRecord() {

    var accountInfo = '';
    var accountName = "Alex Ferguson";
    var primaryContactId = "25A17064-1AE7-E611-80F4-E0071B661F01"; //-- Abraham McCormick
    var primaryContactName = "Abraham McCormick";
    var accountCategoryCode = Category.Standard;
    var annualRevenue = 7500000;

    var entityData =
    {
        "name": accountName,
        "revenue": annualRevenue,        // Currency (money type) ---Display Text = Annual Revenue
        "donotphone": false,    //Two Option (boolean type) ---Display Text = Do not allow Phone Calls
        "address1_longitude": 112.512634,     //Floating Point Number (decimal type) --- Display Text = Address 1: Longitude
        "address1_composite": "This is address 1",  //Multiple Lines of Text (memo type) --- Display Text = Address 1
        "accountcategorycode": accountCategoryCode,     // Option Set --- Display Text = Category
        "primarycontactid@odata.bind": "/contacts(" + primaryContactId + ")" //--- Lookup --- Display Text = Primary Contact
    }

    Xrm.WebApi.online.createRecord("account", entityData).then(
                function success(result) {
                    //Success - No Return Data
                    accountId = result.id;
                    var accountInfo = '';
                    accountInfo += 'Account Name = ' + accountName + '\n';
                    accountInfo += 'Primary Contact = ' + primaryContactName + '\n';
                    accountInfo += 'Category = Standard \n';
                    accountInfo += 'Annual Revenue = ' + annualRevenue + '\n';

                    alert("Account created. Details are given below : \n\n" + accountInfo + "\n\n" + "Going to update this record now.");
                    updateRecord();
                    //return accountId;
                },
                function (error) {
                    alert(error.message);
                }
            );
} 

function executeCRUDOperationsByWebAPI() {
    createRecord();
}

Reference: https://docs.microsoft.com/en-us/dynamics365/customer-engagement/developer/clientapi/reference/xrm-webapi

Filter Subgrid in Dynamics 365

In our day to day tasks related to dynamics 365 CRM, sometimes we need to filter Subgrid dynamically (placed on an entity form) based on data of some fields on the form. In this article, I am going to explain the same using JavaScript code.

Suppose the Subgrid name is “Booking”. This grid load records from an entity “bookable resource booking”. Our requirement was to filter this grid on the fly based on specific category value selected from an option set named “Category”. Here is the complete code.

function filterBookingsGrid(executionContext) {
    //---Get the form context using execution context
    var formContext = executionContext.getFormContext();

    //---Suppose there is a subgrid named "Booking" placed on your entity's form
    var conSubGrid = formContext.getControl("Booking");

    var category = null;
    if (formContext.getAttribute("new_category").getValue() != null) {
        category = formContext.getAttribute("new_category").getValue()[0].id.replace("}", "").replace("{", "");
    }

    //Create FetchXML for sub grid to filter records

    //Set Grid to Empty if Technician is Null
    var fetchXml = '<fetch version="1.0" output-format="xml-platform" mapping="logical" distinct="false">'
                + '  <entity name="bookableresourcebooking">'
                + '    <attribute name="bookableresourcebookingid" />'
                + '    <order attribute="bookableresourcebookingid" descending="true" />'
                + '    <filter type="and">'
                + '      <condition attribute="bookableresourcebookingid" operator="null" />'
                + '    </filter>'
                + '  </entity>'
                + '</fetch>';

    if (category != null) {
        //Show Related Scheduled Bookings
        fetchXml = '<fetch version="1.0" output-format="xml - platform" mapping="logical" distinct="false"> '
                    + '<entity name="bookableresourcebooking" >'
                        + '<all-attributes />'
                        + '   <order attribute="createdon" descending="false" /> '
                        + '   <filter type="and"> '
                        + '       <condition entityname="BookingStatus" attribute="name" operator="eq" value="Scheduled" /> '
                        + '       <condition attribute="new_category" operator="eq" value="' + category + '" /> '
                        + '   </filter> '
                        + '<link-entity name="bookingstatus" from="bookingstatusid" to="bookingstatus" link-type="inner" alias="BookingStatus">'
                        + '<attribute name="bookingstatusid" />'
                        + '</link-entity>'
                        + '</entity > '
                    + '</fetch > ';
    }
    formContext.getControl("Booking").getGrid().setParameter("fetchXml", fetchXml);

    //Refresh grid to show filtered records only.
    formContext.ui.controls.get("Booking").refresh();
}

Dynamics 365: Insufficient Permissions issue while opening record from a Specific User

While working on a project, I faced the following error when opening any activity records from a user with a specific business security role.

1.png

We checked the security role of that user and verified that role has full read privileges on activities and regarding case entity as well but still, it was not working. I checked from google, found some links like given below

https://www.powerobjects.com/2015/02/13/access-denied-identify-fix-security-role-issue/

https://community.dynamics.com/crm/f/117/t/102666

I have verified and tried whatever mentioned in these links in our scenario but nothing worked.

There is another possible solution mentioned in this article, which is focused on creating a new role from scratch.

https://www.inogic.com/blog/2016/11/minimum-privileges-required-to-login-microsoft-dynamics-365/

But, many experts at community forum recommend creating new roles by copying some existing role. So, that’s what I have used to resolve this issue. But, that is not the only thing which I have done. For details, please go through the full article below.

After trying different options and some RnD, I discussed with a teammate about the issue and decided to make a brand new role using an existing default role which has minimum permissions in CRM i.e. Customer Service Representative.

2.png

We created a new role using the following option on an existing role

3

Let’s say the new role name is “My New Role”

4.png

After creating this role, I assigned it to my user and tried to open the activity record and it was working fine.

But the permissions set in this role were not the actual permissions on different entities which were needed to use for a particular user. So, what I need to do is to merge newly created role with my old security role which contains permissions on certain entities for that user. To merge both roles, I used a plugin in XRMToolBox named “Security Role Merge”.

5.png

After opening this plugin and connecting with CRM Organization, press “Get Roles” button.

6.png

All roles from your CRM organization will be populated in the box under “Select Roles to Merge”.

Select multiple roles which you need to merge, and press the “Merge” button

7.png

A message will be shown to you to enter a new role name which will be the resultant role of this merger activity.

8.png

I gave it name as “My Merged Role”

9.png

Now, I removed the old role from the user and deleted that from CRM. Assigned this newly merged role to the user and was able to open all activity records without any issue. After this is done, obviously I need to remove extra permissions for some entities from this new role which my user do not need. That’s it.