{Quick tip} : Determine if OpportunityClose dialog is opened for “Close as Won” or “Close as Lost” in Dynamics 365 Unified interface.

As many of us know, for unified interface now we can customize the “opportunityclose” entity. A feature awaited for a very long time and finally it’s here.

If you are not aware, you can now customize the dialog box that pops up when you click “Close as Won” and “Close as Lost” button on the opportunity. The entity is “opportunityclose” entity. For more details, please refer the below links

https://docs.microsoft.com/en-us/dynamics365/sales-enterprise/enable-opportunity-close-customization

https://docs.microsoft.com/en-us/dynamics365/sales-enterprise/customize-opportunity-close-experience

So you can customize the opportunityclose form and add your custom fields as well. But the same form fires both when you click “Close as won” or “Close as lost” button. My customer had a requirement where based on the button clicked, appropriate fields need to show up and certain business logic need to be performed when the “Opportunity Close” form is loading.

Just when I was about to pose before my customer as “know it all person”, Dynamics 365 again intervened and put me in proper place. So I was back to drawing boards. The first thing that struck me was – “How is this quick create form getting launched?”. In the ribbon workbench I evaluated “Close as won” button and found the below action.

image

Now we are going to modify the Opportunity system library script file. Ahhhhhhhhh..Just joking.

The important thing to note here is the “Boolean parameter” which is passed to the function. So the key takeaway from here is the system function is taking this boolean parameter as input and then passing this parameter to the Quick create form of opportunity close.

Now things are sorted out. A quick guess – this parameter must be passed as a Querystring parameter to the Quick create form. And hell yeah! I was right.

function formLoad (e) {
        debugger;
        var isCloseAsLostClicked = false;

        var fc = e.getFormContext();
        var gc = Xrm.Utility.getGlobalContext();

        var queryString = gc.getQueryStringParameters();
        isCloseAsLostClicked = queryString["param_won"];
// value will be true for won and false for lost button click.    

}

I have highlighted the lines of code here which will help you determine whether “Close as Won” or “Close as Lost” was clicked.

Once you have that information, it’s up to you to utilize this information. Cool isn’t it?

Before I end, this will work for Unified interface only as the feature of customizing opportunityclose entity is supported only for Unified interface.

P.S – Haven’t found this documented in MS docs. So obviously can’t vouch whether this parameter will always be there. As of now validated for multiple environments and scenarios and it worked just fine. Would be happy for alternatives.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Advertisements

How to use Promise to evaluate your ribbon enable rules with asynchronous Xrm.WebApi methods in Dynamics 365 Unified interface.

We all have been using Xrm.WebApi methods isn’t it? After all why not? They are wonderful. You no longer need to write lengthy XmlHttpRequests and parse the raw JSON results back. Xrm.WebApi methods does the hard part of converting the raw JSON outputs into strongly typed objects.

Not sure if anyone is still there but if you are new to Xrm.WebApi methods, below is the perfect link to get you started.

https://docs.microsoft.com/en-us/powerapps/developer/model-driven-apps/clientapi/reference/xrm-webapi

Just when you are about to think that Xrm.WebApi methods have successfully ticked all the boxes, comes the ribbon rules. Xrm.WebApi rules are asynchronous.

Suppose you have a requirement where you need to show a ribbon button only if user is in role of Salesperson. For that we write one function “userHasRole” with the code below

 function userHasRole() {

       var isUserAdmin = false;

        Xrm.WebApi.retrieveMultipleRecords("role", "?$select=roleid&$filter=name eq 'salesperson'").then( 
            function success(result) { 
                 var userSettings = Xrm.Utility.getGlobalContext().userSettings; 
                var securityRoles = userSettings.securityRoles;

                var isUserAdmin = false; 
                 for (var i = 0; i < result.entities.length; i++) { 
                     var roleId = result.entities[i].roleid;

                    if (securityRoles.indexOf(roleId) !== -1) { 
                         isUserAdmin = true; 
                        break; 
                    } 
                } 
            }, 
            function (error) { 
                console.log(error.message); 
            } 
         );

return isUserAdmin; 
}

The problem with this code is very evident. Before Xrm.WebApi return the results, the function would return false. Off course you can modify this function using window level objects and then using Xrm.Page.ui.refreshRibbon() to refresh the ribbon after Xrm.WebApi returns results. And perhaps we all have done that so far.

While the above method would certainly work, you may think like – “Is this the only way?” Certainly not. If you are using Unified interface (only option left for online users after Oct 2020), you have a better way to achieve the same. Unified interface rules support returning a Promise rather than boolean for asynchronous rule evaluation. Let’s see how we can re-write the same rule using Promise. And surprisingly, many of us working in Dynamics 365 day in and day out are not aware of this.

function userHasRole() { 
    return new Promise(function (resolve, reject) {

        Xrm.WebApi.retrieveMultipleRecords("role", "?$select=roleid&$filter=name eq 'salesperson'").then( 
            function success(result) { 
                var userSettings = Xrm.Utility.getGlobalContext().userSettings; 
                var securityRoles = userSettings.securityRoles;

                var isUserAdmin = false; 
                for (var i = 0; i < result.entities.length; i++) { 
                    var roleId = result.entities[i].roleid;

                    if (securityRoles.indexOf(roleId) !== -1) { 
                        isUserAdmin = true; 
                         break; 
                    } 
                 }

                // return true or false 
                resolve(isUserAdmin); 
            }, 
            function (error) { 
                reject(error.message); 
                console.log(error.message); 
            } 
        ); 
    }); 
}

Not much change in the code. All you need to do is return a Promise the resolve method of which should return true or false depending on business logic. And one very important to remember is that not only with Xrm.WebApi methods but also if you are using XMLHttp async, it would work just fine.

Put your code within the Promise and everything works like charm.

Any functionality before we implement, we should be aware of the limitations of the same. So we have a couple of them here.

  • This only works for Unified Interface. If you are using WebClient this won’t work
  • If the rule does not evaluate within 10 seconds, the rule would resolve with false value

Before I end, you may be asking where should can I find this in Microsoft documentation. Well if you are a big fan of Microsoft docs like me, here you go – https://docs.microsoft.com/en-us/dynamics365/customerengagement/on-premises/developer/customize-dev/define-ribbon-enable-rules#custom-rule

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Dynamics 365 integration with SmartSheet using Flows–What’s there and what’s not.

A dry spell of a month and here I am back to my favourite way of connecting with community which is writing one more blog post.

So here I got a new requirement from my customer. Basically they are using Smartsheet and Dynamics 365 and the simple requirement is whenever any changes are made in the smartsheet (row added or updated), some updates need to happen back in Dynamics 365.

Although I haven’t used Smartsheet connector in Flow, I was just aware of it and my initial hunch was like this would a walk in the park for flows. But like so many other times, this time also it didn’t quite turnout like the way we expected.

The first scenario was “When a row is added to a smartsheet”, I should be able to sync those changes to Dynamics 365 instance. So I started creating and flow and searched for Smartsheet connector. And the trigger is just there.

“When a new row is created”

image

I select that trigger and connect to the smartsheet.

image

As you can see from the above screenshot, I provided the smartsheet I want connect to and also mentioned the columns that I want to sync to. “Requestor” and “Business Group” are columns in the smartsheet as seen from the below screenshot.

image

The next step is to identify the values of the fields entered by the user. Now this one can be tricky if you are new here. For this demo I will use the Initialize variable action and take the value of the Requestor and Business Group in those variables. But before we do that, we need to understand how does it return the data.

So I go ahead and add a new row to the Smartsheet. As expected within a minute the flow fired. Let’s inspect the body of the flow here.

image

As seen from the above screenshot, it returns cells collection. The value highlighted here is for the" “Business Group” field.

To take this value and assign it a variable you can use the below expression.

triggerBody()[‘cells’][0].displayValue

image

In this way you can use variables for other values and then use CDS connector to update CRM.

Now comes the update part. Surprisingly there is no trigger for when a row is updated in Smartsheet.

image

We have something – ‘When a sheet is update’ but unfortunately that does not return the updated rows. Infact it returns the whole sheet data. Kind of stuck and hence had to resort to custom development of consuming SmartSheet API’s.

Would be delighted if I have some inputs here!

Hope this helps next time you get a requirement on this.

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

{Solved}WebAPI methods in PowerApps component framework (PCF) custom control returning null–Dynamics 365

PowerApps component framework has been like a tsunami hitting the power platform. From customer standpoint, now they are able to achieve any custom UI which otherwise all these days would come back as – “Not supported by Dynamics” from a CRM architect/ consultant. Not only for customers, PCF have been a shot in arm for developer community who finally find their footing in Power platform where they have something unique to contribute, specially those coming from pure web development experience.

PCF controls are everywhere. And if you have developed a PCF control, chances are you must have used the WebAPI methods to interact with CRM data and bind them in PCF controls. To interact with the WebAPI methods, you need to use the context object that gets passed to the init method of your control. For example if you want to create a record, you can use – context.webApi.createRecord method.

The below article explains the  important properties you can access through the context object.

But recently I have been getting loads of queries that context.webApi methods are returning null. Meaning if I try to use the same statement – context.webApi.createRecord.

Honestly I was bit surprised as I have already developed quite a few but didn’t face this error. So decided to give it a try. I took a control I have developed month’s earlier and then tried to re-use it in a latest trial environment. To my surprise, even I was getting that error.

After much try and error and searching the entire manifest documentation with keyword – “webapi”, I came across this Microsoft docs article for schema reference – https://docs.microsoft.com/en-us/powerapps/developer/component-framework/manifest-schema-reference/uses-feature

Pic courtesy – Microsoft Docs.

image

Basically we need to use the “feature-usage” tag and use the WebAPI feature explicitly. Once I put this tag and rebuilt the control, everything just worked fine.

What I believe is with some release Microsoft made it mandatory to use these as opt in feature. Unless we explicitly specify some objects to the load, it won’t load at runtime. Perhaps it’s a way to optimize the performance.

So next time if you get this error, you know which magic tag to include.

Hope this help!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

Issues with self signed certificates for server-server integration between CRM and Sharepoint? Here is what you may need to know to save your day.

As promised in my last blog, I am back with one more scenario where consultants get stuck in on-premise environments. Server-server SharePoint integration with Dynamics is something we take for granted when we set up trial instances for demo in online environments. After all, entire internal plumbing is handled by Microsoft and we just need to do follow some sequential steps to accomplish the same.

However things are not so rosy for on-premise systems. You have to follow a host of steps as detailed out in this article – https://docs.microsoft.com/en-us/previous-versions/dynamicscrm-2016/administering-dynamics-365/dn949332(v=crm.8)

One of the requirements for server based integration is Sharepoint should be SSL enabled. And many a times, you need to set this up with self signed certificates to create a working POC before customer approves it. This post specifically deals with all the problems that you might face while setting up server based integration using self signed certificates. The post will highlight some of key errors usually encountered and how to resolve the same.

Before you proceed with the below error scenarios, just make sure you followed the below prerequisite steps – https://docs.microsoft.com/en-us/previous-versions/dynamicscrm-2016/administering-dynamics-365/dn949332(v=crm.8)#other-prerequisites-and-limitations

Error 1: CertificateData for CertificateType: S2STokenIssuer not found

This error is usually thrown in the after providing the Sharepoint site name and SharePoint Realm ID in the “Enable server based SharePoint integration” configuration screen.

This usually happens if you miss the step to add the server-server certificate to Microsoft Dynamics 365 configuration database as explained here – https://docs.microsoft.com/en-us/previous-versions/dynamicscrm-2016/administering-dynamics-365/dn949332(v=crm.8)#add-the-server-to-server-certificate-to-the-local-certificate-store-and-microsoft-dynamics-365-configuration-database

You would need to open PowerShell in administrative mode in CRM server and then navigate to <drive>:\Program Files\Microsoft Dynamics CRM\Tools folder. Then run the below command.

.\CertificateReconfiguration.ps1 –certificateFile <certificate pfx file location> -password <private certifacte password> -updateCrm -certificateType S2STokenIssuer 

-serviceAccount <service account for CRM Async service> -storeFindType FindBySubjectDistinguishedName

 

Error 2: Certificate private key is not found

This error is thrown when we run “CertificateReconfiguration.ps1” power shell script as described above. But why this error?

To be honest, I am not a certificate expert and I am not sure why this happens. But after multiple trial and error I was able to workaround the problem. And I am going to share that.

There are multiple ways to create a certificate. So what options we have. I am going to discuss the commonly used one and what error you may get for each.

Option 1 – Using IIS

If you search in Google on how to create a self signed certificate, the first article that may catch your attention is to create a self signed certificate from IIS.

image

You create the certificate but you will find the certificate does not have a private key with it. And hence it won’t work while you run the above powershell command.

Option 2 – Using PowerShell command

The next one that is suggested for Windows 10 and above is using Powershell command – “New-SelfSignedCertificate” . The below command would create a certificate and store in Personal store.

New-SelfSignedCertificate –DnsName <You CN name for certificate> -CertStoreLocation “cert:\LocalMachine\My”

This one created has a private key associated with it but if you try to run the powershell script  – “CertificateReconfiguration.ps1” you get the error – “Certificate private key is not found”. This is surprising because the certificate has a private key associated with it.

Option 3 – Using MakeCert.exe

After much googling around, one of the community blogs suggested to use MakeCert.exe to create the self signed certificate and it might work. So tried the below commands.

makecert -r -pe -n "CN=HOSTNAME" -eku 1.3.6.1.5.5.7.3.1 -sky exchange -sv HOSTNAME.pvk HOSTNAME.cer

The above command will create a certificate file and a private key file. Make sure to replace hostname with value for your environment. But we need a .pfx file to run our PowerShell command. To create a .pfx file out of this, please run the below command.

pvk2pfx -pvk HOSTNAME.pvk -spc HOSTNAME.cer -pfx HOSTNAME.pfx

Once the .pfx file is generated, you can import the file in personal store and use this for your SharePoint SSL binding. Once done execute the PowerShell command – “CertificateReconfiguration.ps1”  and it should work just fine.

As you can see from the above, you need couple of .exe files to make this work – makercert.exe and pvk2pfx.exe. But where do I get them?

Unlike what I thought, it was quite a hassle to get it. MakeCert.exe shipped with Visual studio till version 2013 and later it was stopped. You can get makecert.exe by installing Windows 8 SDK. But if you are using windows 10 and above, that is an issue as well. Windows 10 SDK is quite a big installation and doing that just to get a standalone makercert file is something which baffled me. After much pain, I was able to get makecert.exe from Fiddler2 installation and pvk2pfx.exe from Windows SDK. To help readers, I have put those files in the one-drive link shared through this blog.

https://debajmecrm.com/2019/08/23/download-makecert-exe-and-pvk2pfx-exe-for-creating-self-signed-certificate/

You can just use these and everything should work fine.

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)

 

Upload multiple attachments in CRM Notes/ annotations with metadata for each attachment- Introducing Notes Manager from XrmForYou.com

It gives me great pleasure to announce the new CRM add-on from XrmForYou stable – Notes Metadata Manager utility from XrmForYou stable.

Well Notes (Annotations) have existed in CRM since pre-historic times. And perhaps one of the most widely used feature in Dynamics till date since its inception. After all it gives a nice way to store your documents along with some notes and description which can be read by CRM users.

However with my many years in consulting, I realized the pain points of customers using Notes as well.

  • Can I upload multiple attachments at one go with Title and description?
  • Can I add new fields in my notes entity (Annotation) to capture some extra information along with Note Title and Note Description?
  • Can I put notes are separate from my timeline control? May be in a separate tab?
  • Can I drag and drop multiple documents in Notes section so that it will automatically upload?
  • Can I create more than one Note record at a time with attachments?

We have progressed leaps and bounds but even with the latest version the answer to most of the questions above is “NO”. Also traditionally since inception, Notes entity was not customizable to add new fields and users were just limited to using only two field “Note Title” and “Note Description”.

For trial and pricing, write to us at info@xrmforyou.com

Well, we have understood the pain and hence we have released this Add-On for you. Works perfectly on UCI in web browser and on tablets and phone as well.

Step 1: Configuration

It comes as a Managed solution. Once you install the managed solution and open up the solution configuration page, you get a screen like one below.

image

The top section is the license information which will be provided by our team.

The section below that shows all the entities which have been enabled for Notes. This is the area where you can configure additional metadata for your Notes records corresponding to each entity.

I click on Account entity and the existing metadata account shows up as shown below.

image

You can create up to a maximum of 10 additional metadata records as per the current release of the tool. The metadata currently supported are of type text and optionset.

image

Above is the way to create a text metadata. Also you can make the additional metadata mandatory to be entered during record creation by setting the Required? field to checked.

Below is the way to create an optionset metadata for your note record.

image

As you can see from above you can configure any global option set and map your Optionset Metadata with that global optionset for the list of possible values.

You save your metadata and that’s all from the Configuration Page.

Step 2: Setting it up on your form

The next step is setting up the custom notes control on the form.To do that you just need to include the custom web resource that comes with our solution on the form where you want to show the control. Detail on the web resource control follows in our actual documentation on our website. www.xrmforyou.com

Once the webresouce is inserted on the form, this is how it looks as shown below. Below are the screenshots in the Unified Interface environment.

image

Inline editing of Note title, Description and metadata.

image

Inline new record creation:

image

Inline search

image

Attachment Upload

image

Bulk Upload

image

Drag & Drop

image

For trial and pricing, write to us at info@xrmforyou.com

Hope this helps!

Debajit Dutta

(Dynamics MVP)

For consultation/ corporate training visit www.xrmforyou.com or reach out to us at info@xrmforyou.com

Our product offerings:

Role based views for Dynamics 365 (http://www.xrmforyou.com/role-based-views.html)

CRM-Sharepoint Attachment uploader and metadata manager (http://www.xrmforyou.com/sharepoint-integrator.html)

Record Cloner for Dynamics 365 (http://www.xrmforyou.com/record-cloner.html)

Multiselect picklist for Dynamics 365 (http://www.xrmforyou.com/multi-select-picklist.html)