Category Archives: Microsoft CRM

You don’t have required permissions to create Azure Active Directory applications–Error while creating Dynamics 365 Portal/ PowerApps portal

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

This is an issue that was recently reported to me. One of the developers from my customer team was trying to provision a portal for their Dynamics 365 environment. But unfortunately he was receiving the below error.

image

The developer here in question here have System administrator privilege in Dynamics 365. Also as per Microsoft recommendation the user had access mode set to Read-Write under Client Access License (CAL)

However if you observe the error carefully here, the issue is not with the user privileges in Dynamics 365/ CDS. Rather the issue is with the user’s permission to create Azure Active Directory application in Azure tenant. But why is that permission required?

When you create a portal, a new application is registered in Azure Active Directory associated with the tenant. The issue is while creating the application, since the user is not having the required privileges to create the application it is failing.

For a portal already provisioned, if you go to Azure Active Directory and navigate to App Registrations section, you should see and Portal APP.

image

So after adding the developer to appropriate user group in Active directory with permission to create an APP, the user was successfully able to provision the portal.

Hope this helps!

Debajit Dutta

(Microsoft MVP)

{CRM Tips from the Vault} How to create scheduled workflows in Dynamics 365/ CRM on-premise. And it’s not using recursive workflow

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

CRM tips from the vault – A series which I have started on request of my blog readers who are quite new to CRM. My blog focus on niche topics which mostly require a prior in-depth understanding of Dynamics 365. However in this series I will mostly cover the topics which are quite simple, used in almost every project implementations and more importantly have withstood the test of time.

Here is my Tip 3 – How to create a scheduled Workflow in Dynamics 365 on-premise to run everyday at specified time?

Before I go ahead and start to explain, few points to remember.

  • This article only considers the workflow capabilities of Dynamics 365 and does not take into account the Power Automate capability of running scheduled flows
  • The article talks only about Dynamics on-premise. However the steps described here will work equally well for Dynamics 365 online

So we have this requirement where we need to run a particular workflow everyday at some specified time. You may be thinking – Why not recursive workflows?

Recursive workflows are good. But they have one problem. If more than seven instances of the workflow are detected in memory, the platform will think of it as an infinite loop situation and then will unload all the existing instances of the workflow. Not to forget the issues of async service and persistent workflows in Dynamics CRM.

So what is the other alternative. Well we can actually easily do it in combination with Bulk Delete operation. Let’s see how we can do the same. To do this I take an example here. Say we need to sync Products and Product Variants from an external site everyday at a specific time.

Step 1: Create a Dummy Entity called Workflow Trigger.

I will create few fields here.

  • Name (Primary Attribute) – To store the name of the operation
  • Workflow type – An option set with two values
    • Product Sync
    • Product Variant Sync

image

Also prefer to create the entity as organization owned. For the requirement mentioned here, this is fine. However based on your requirement you can add more fields to this entity.

Step 2 – Create a Bulk Record Deletion Job

Navigate to Settings –> Data Management – Bulk Record Deletion and then click on Bulk Record Deletion.

Create new Bulk Record Deletion record. In your search criteria use the Workflow Trigger Entity.

image

Set the scheduled time. Currently the job is scheduled to run to run everyday at 12:00 AM. You need to set the time as per your requirement.

image

Complete the process to create the Bulk Deletion record job.

Step 3 – Create couple of Workflow Trigger Records

I go ahead and create couple of Workflow Trigger record for each operation. One for Product sync and the other for Product variant sync

image

Step 4 – Create a Workflow on Delete on Workflow trigger record.

We are at the final step where we will go ahead and create a workflow. The workflow shall fire on delete of Workflow Trigger record. As you can see when the workflow trigger record of type Product Sync is deleted, I invoke an action which will internally sync the products. And then I re-create a workflow trigger of type “Product Sync”

The same I do for Product Variant Sync.

 

image

Just activate the workflow.

Now we are all set and done. So we have done a lot of steps. But how does that help our requirement. Let’s see what happens in sequence.

  • At 12 AM, the Bulk delete operation runs and deletes both the Workflow trigger records
  • When the workflow trigger records are deleted, the Workflow which we set up on delete of Workflow Trigger fire.
  • Inside the workflow we are checking the type of Deleted record. If the Workflow Type = Product Sync then we are calling the action which internally syncs the product with Dynamics 365
  • After the action is called, we re-create the Workflow trigger record. This is a very important step as when the next time the Bulk delete operation runs, it will again delete the record which we just re-created in the workflow and this cycle will continue for every day.

And voila! We have achieved our goal of setting up a scheduled workflow which shall run everyday at a specified time.

Before I end, while this is very good process, it has it’s own limitation bounded by the limitations of Bulk delete operation. You can only earn a bulk delete operation once day at a specified time. If you have a requirement say in our case to sync products every couple of hours, this methodology won’t work.

Hope you find this trick useful.

Debajit Dutta

(Microsoft MVP)

Add/ remove/ modify JSON elements of a JSON array in Power Automate/ Microsoft Flow

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

Power Automate is like a continuously evolving engine adding more power to it with every release by Microsoft. I still remember the limited functionality it had when it was introduced. Looking back to then and now, it’s been an evolution of Power Platform and Power Automate as well. Not only the name has been changed from Microsoft Flow to Power Automate, even the underlying functionalities have evolved a lot.

And one of them is the capability to work with JSON objects. With the world moving away from SOAP to REST based services, JSON have become the primary format of data exchange between environments.

And here is one such requirrement. Where I needed to Add/ remove and modify the incoming JSON request. So I had an incoming JSON in the following format.

[
    {
       "x_200_fname": "debajit",
       "x_200_lname": "dutta",
       "x_200_trantime": "6/20/2020"
    },
    {
       "x_200_fname": "Gabriel",
       "x_200_lname": "Canata",
       "x_200_trantime": "1/15/2020"
    }
]

As you can see, it’s  a JSON array with three properties in there. No I had few things to do with the array.

  • Change the properties like “x_200_fname” to more readable property like – “firstname. Similarly for “x_200_lname” to lastname and “x_200_trantime” to transactiondate.
  • Add a new property to the JSON called “fullname” which is combination of first name and last name
  • Modify the x_200_trantime to a suitable date format. For example an incoming date in the format 6/20/2020 should be formatted to 6 Jun 2020.

So I will modify the JSON as per the requirements stated above and then pass it on. Understand iterating through the array won’t help here. It is is more of like we get an incoming JSON, modify the JSON properties and then pass the JSON forward to be processed downstream.

Honestly I thought I am going to hit hard luck here. However after lot of searching I got the “Data Operations – Select” from Power Automate.

image

And then I get the wonderful data operation. As you can see, I have created one custom property called fullname. Also have modified the incoming property name and property value as well like the transactiondate.

image

And then when I run the flow, below is the output post select operation. Wonderful isn’t it?

image

Hope this helps!

Debajit Dutta

(Microsoft MVP)

Prevent Save and create new on Quick create form in Dynamics 365/ CDS

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

Our life as consultants can be quite amusing. Sometimes we have a customer who complains about a simple feature not being present in Dynamics 365 and then when Microsoft finally puts it on the table, we have one customer who does not want that feature itself.

Well, customer is GOD. Can’t complain about it. After all they pay the bills. And here I am going to talk about one such feature – “Save and Create New” feature in Quick create forms.

With the October 2019 preview release of the Unified Interface for model-driven apps in PowerApps we have added an option to quickly save a record and create a new one directly from the Quick Create Form. This new button action will make it much easier for users to quickly add a record, save it and start working on another record of the same type directly from the Quick Create form.”

-Courtesy Powerapps documentation.

 

If you still not finding relevance you can read this article. Basically this is what I am talking about.

image

One fine morning at work, my customer walks up to me and asks me remove the Save & create new button. And guess what! their business case seems to be quite valid. They shall launch a quick create on click of a ribbon button and then the user should be allowed to create only one record. Quite reasonable right?

I did a bit of search and found that this behavior cannot be removed. So obviously the next choice is to stop the “Save & Create New” event. And guess what. Microsoft allows you to distinguish between “Save and Close” and “Save & Create New” click. You can do that using our very old getSaveMode() function of save event argument. Will come to the code in a bit.

So basically when the Save & Create New button is clicked, user should be informed – “Save &Create New functionality is not allowed.”. And it should be without any pop-ups which our customer seriously dislikes.

So here is our final solution. I write a simple JavaScript and put it on the Quick create form and then hide it on the form.

Then I go ahead and add the below on save of the lead quick create form.

function leadQuickCreateSave(e) {
    var fc = e.getFormContext();
    var args = e.getEventArgs();
    var saveMode = args.getSaveMode();

   if (saveMode === 59) { // save and create new
       fc.ui.setFormNotification("STOP_SAVE", "ERROR", "Save & Create New functionality is not allowed.");
       args.prevenDefault();
    }
}

And now when everything is published, I just try to use the “Save & Create New” functionality and it work’s just great!

image

Hope this helps!

Debajit Dutta

(Microsoft MVP)

{CRM tips from the vault} Tip 1–Custom “Qualify Lead” button on Dynamics 365 From

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

CRM tips from the vault – A series which I have started on request of my blog readers who are quite new to CRM. My blog focus on niche topics which mostly require a prior in-depth understanding of Dynamics 365. However in this series I will mostly cover the topics which are quite simple, used in almost every project implementations and more importantly have withstood the test of time.

Here is my Tip 1 – Custom “Qualify Lead” button on Dynamics 365 form.

First of all, why is a Custom “Qualify Lead” button required? After all we have the wonderful Out of the box Qualify Lead button which converts a lead to opportunity. But sometimes it doesn’t work because your business need more

Right now this is the default behavior when you click on Qualify lead Button.

image

You get an option to Qualify the lead with an existing account and contact or you can go ahead and make them blank to create a new Account and Contact.

If you click Continue here, the lead shall be converted to opportunity.

Well, that’s fine. But what if you wanted to take control of this lead Qualify functionality? What if you want to open a custom HTML webresource pop-up with additional information to display to the end-user.

In situations like this, we shall need to use a custom Qualify button and hide the OOB one. In this blog, we are only going to concentrate for Dynamics 365 forms.

To modify the Lead ribbon, I will use the wonderful ribbon workbench editor. A time tested classic by Scott Durow. You can download the ribbon wokbench from here.

Once you have downloaded the ribbon workbench, install it and then open up your lead entity in ribbon workbench editor.

Find out the ribbon element with Id = “Mscrm.Form.lead.ConvertLeadQuick”

image

image

The next thing I usually find developer’s doing is hide this button and then come up with completely new custom Qualify button. However the issue with that is you need to re-define all your enable rules and display rules. Understand Qualify button should show up only depending on certain conditions. If you remove the enable and display rules, you need to redefine these conditions on your custom button.

If your goal is to just to override the Qualify button click, we won’t create a new button. Rather we will just go ahead and override the click event handler. Let’s try to do this here.

Right click on the button and click on Customize Command.

image

Then under Commands section select the Command and modify Custom JavaScript Action.

image

As you can see there is Library and Function name. Right now it is pointing to system library and function. All you need to do is create a custom JavaScript and put your own handler.

As you can see from the below screenshot, I have used a custom library and Javascript function on Qualify Lead click. Also make sure to pass PrimaryControl as your function parameter. This will be your form context in case you need to access your form fields within your handler.

Similarly if you want to add a custom enable rule, you can do the same by adding one more enable rule to the list of enable rules already in place. If your business requirement need, you can even remove a OOB enable rule.

Make sure you publish your changes before you leave the ribbon workbench editor.

Hope this helps!

Debajit Dutta

(Microsoft MVP)

Copy Notes with Attachments when a lead is qualified to Opportunity in Dynamics 365

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

Starting from templates is a great way to start learning flows” – This is one of the recommendations I learned during my preparation for Microsoft Certification.

And I realized it today when I had to solve one requirement for my customer. So the requirement was to copy notes from a lead to the opportunity record when the lead is qualified. Quite a simple stuff. If you are a Dynamics 365 Pro, you may be thinking – Isn’t it something which Dynamics 365 does OOB.

Yes it does. But does it really copies of the Notes to Opportunities? Let’s explore this a bit more.

So I have this lead and I have added a Note – “Lead Note 1”. Also observe I have an attachment in the note.

image

Now I qualify this lead to Opportunity. Once the lead is qualified to Opportunity, I could see the Lead Note showing up in Opportunity timeline as well.

image

Well it’s done right? Not quite. And trust me, superficially it shows up in the Opportunity entity timeline and many believe that it is being copied over to Opportunity. But in-fact, it is still tied to Lead. To verify this, I open up Advanced Find and search for this note record. I could see only one note record and that too being attached to the lead record.

image

So we understood, it really didn’t copy over the Note. So now how do I accomplish this? Just when I was about to write my flow, I came across this by chance in the existing templates.

image

Such a useful template by CRM Innovation LLC. It’s just an addition to all the great work they are already doing for Dynamics Community.

All you need to do is open up this template and then set up the connection with your CDS/ Dynamics 365 environment accordingly.

image

And now when I qualify the lead to opportunity, I can see the Notes record getting copied over along with attachment (if any) to the Opportunity record.

To verify in advanced find, I have now two notes record – one for lead and one for opportunity.

image

A very good learning for me. And hope you found it interesting too!

Debajit Dutta

(Microsoft MVP)

Parse XML in Power Automate/ Microsoft Flow

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

The simplest of things are sometimes the sweetest. And here is this one requirement to parse an XML using Power Automate/ Microsoft Flow.

With SOAP giving away to REST based API’s, XML parsing is gradually going out of fashion. But still there are some scenarios where you need to go ahead and do XML parsing. So let’s see how can you do that in Microsoft Flow.

Let’s say you have the following input XML.

<response>
   <status>failure</status>
   <reason>duplicate</reason>
   <recordid>0123456789</recordid>
   <url>https://www.google.com</url>
</response>

What I want is to take a decision based on the status value. So let’s see how I can do this.

Here is the Input Xml.

image

The next step we need is to parse the XML. For that we will use the Compose Action.

In the inputs section, we use this formula – xpath(xml(outputs(‘Input_Xml’)), ‘string(/response/status)’)

image

As you can see in the above step, we are using the xpath formula and then try to parse the status field using the path  – /response/status and then typecasting it to string using the string() construct. Please note that the typecast is necessary. Otherwise the returned results will be an array.

Next we use the Initialize Variable action to set the value from the output of the previous Compose step.

image

And below is the test run.

image

As you can see, we are able to successfully parse the Status field from XML. You can now use the Status field for further processing.

Off-course, the complexity of the XML may vary. But the logic remains same.

Hope this helps!

Debajit Dutta

(Microsoft MVP)

Retrieve contents of File Data Type field in Dynamics 365/ CDS using JavaScript/ client code.

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

Few months back I wrote an article on File Data type in Dynamics 365/ CDS where I explained the details of this data type and explained how you download the content of the field using C# code.

After that I received loads of request on how I can do the same using JavaScript. And here is this blog where I show in detail on how you can do that.

For this demo, I have created a file data type field on contact entity – File Content (cr947_filecontent)

image

Then I go ahead an upload a file on one contact record.

image

Ok now the tough part. How to download this file content from your client script if required? Well, let’s see how you can do this.

First things first. Below is the URL Format to download the file content for a file field for a contact record.

https://<crmurl>/api/data/v9.1/contacts(<contact_id>)/cr947_filecontent?size=full – This will download the content in base64 format string.

https://<crmurl>/api/data/v9.1/contacts(<contact_id>)/cr947_filecontent/$value?size=full – This will download the content as byte array.

If your file size is less than 16 MB, then depending on how you want to download the file, you can use the appropriate URL.

However if your filesize is more than 16MB, it wont’ work. This is because you if you use the same URL to download the content for a filesize more than 16MB, you will get an error – “Maximum file size supported for download is [16] MB. File of [17 MB] size may only be downloaded using staged chunk download.”

So let’s see how we can have a common function to handle all these scenarios. Below is the code for the same. I have decided to go ahead with the base64 content.

Also if you observe here, I am downloading the file content in chunk of 4MB. Also observe I am using the “Range” header to set the bytes count that I want to download.

function makeRequest(method, url, startBytes, increment) {
    return new Promise(function (resolve, reject) {
       var request = new XMLHttpRequest();
       request.open(method, url);
       request.setRequestHeader("Range", "bytes=" + startBytes + "-" + (startBytes + increment - 1));
       request.onload = resolve;
       request.onerror = reject;
       request.send();
    });
}

async function PrepareFile() {
    var startBytes = 0;
    var increment = 4194304;
    var url = "https://<crmurl>/api/data/v9.1/contacts(8da6e5b9-88df-e311-b8e5-6c3be5a8b200)/<field_name>?size=full";
    var finalContent = "";
    var fileSize = 0;
    var fileName = '';

   while (startBytes <= fileSize) {
       debugger;
       var result = await makeRequest("GET", url, startBytes, increment);
       var req = result.target;

      if (req.status === 206) {
          finalContent += JSON.parse(req.responseText).value;
          startBytes += increment;

         if (fileSize === 0) {
             fileSize = req.getResponseHeader("x-ms-file-size");
             fileName = req.getResponseHeader("x-ms-file-name");
          }
       }
    }
}

PrepareFile();

I am calling PrepareFile() method which is doing the loop through. “finalcontent” is the variable which will have the entire base64 content.

How to use the base64 content and download it through browser? I am leaving that for a homework.

Hope this helps!

Debajit Dutta

(Microsoft MVP)

Custom integration between Dynamics 365/CDS and SharePoint using C# and SharePoint REST API ? Learn how to create a SharePoint Add-in and generate authentication token–Part 2

Follow my blog for more interesting topics on Dynamics 365, Portals and Power Platform. For training and consulting, write to us at info@xrmforyou.com

If you are directly on this blog, I suggest you go through the first blog of this series.

In our previous blog, we created the SharePoint Add-in. In this blog we shall be providing this APP permissions on sitecollection.

To apply permissions to the generated Add-In either you can visit SharePoint Tenant Administration Site or via AppInv.aspx page

Visit SharePoint Admin center to do this. Go to <admin_site_url>/_layouts/15/appinv.aspx

image

Use the App Id that you created as per directions in previous blog and click on Lookup button to retrieve the APP Details.

image

The important thing is the App’s permission.

If you want to provide full control at the tenant level use the following permission XML

<AppPermissionRequests AllowAppOnlyPolicy="true">

<AppPermissionRequest Scope="http://sharepoint/content/tenant" Right="FullControl" />

</AppPermissionRequests>

image

Once you click Create you will be presented with permission dialog. Click Trust It to grant permissions

clip_image002

Now your Add-In is ready for use. As we granted tenant-level permissions you might be wondering if I need do the same for specific site collection. No worries this can he handled as well. Create Add-In app in your Site Collection using Blog Post 1 and follow the similar approach but modify the permissions XML as below:

<AppPermissionRequests AllowAppOnlyPolicy="true">

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection" Right="FullControl"/>

<AppPermissionRequest Scope="http://sharepoint/content/sitecollection/web" Right="FullControl"/>

</AppPermissionRequests>

In this way we create Add-Ins and grant permissions to Add-In. In Part-3 of my blog I will show you how to generate token from Add-in.

Hope this helps!

Debajit Dutta

(Microsoft MVP)