Left Join with Not-in operator in FetchXml in Microsoft Dynamics CRM 2013

Just the other day, I was discussing with one of my colleagues about his experience of building fetch xml reports for one online implementations and we stumbled upon the topic where he needed to show the list of accounts with no cases associated to it. With SSRS reports it’s just a simple query. However for online, we have to limit our self with fetch xml reports and till 2011 version of CRM, it was not possible to construct a query of left join with NOT-IN operator.

But in dynamics 2013, you can construct the query to do this. The following is the query to retrieve the list of accounts with no leads. The sample code is taken from MSDN.

<fetch mapping=’logical’>
  <entity name=’account’>
    <attribute name=’name’/>
    <link-entity name=’lead’ from=’leadid’ to=’originatingleadid’ link-type=’outer’/>
    <filter operator=’and’>
      <condition entityname=’lead’ attribute=’leadid’ operator=’null’/>
    </filter>
  </entity>
</fetch>

For full documentation refer to the link : http://msdn.microsoft.com/en-in/library/dn531006.aspx

Hope this helps!

Advertisements

Switch Forms in Microsoft Dynamics CRM depending on Business Logic

Recently in our project, we had a requirement where the customer wanted to show different forms of the same entity depending on some business logic. Off-course we could design the form with multiple sections with appropriate fields and show/ hide the sections based on business logic.

However if the above approach does not suit you, you have the Xrm Scripts in CRM 2011 and CRM 2013 to enable you to switch forms dynamically. Please check for the pseudo code below. All you need to to set up a default form for the entity. In the default form load check your logic and perform the redirection as required.

var formId= “<Id of the form to navigate>”

if( logic == true )
{
   Xrm.Page.ui.formSelector.items.get(formId).navigate();
}

To get the Id of the form to navigate to, you can write the following code in the onload of the form and copy it and use it in the default form.

var currentFormId= Xrm.Page.ui.formSelector.getCurrentItem().getId( );

Please note that getCurrentItem() method would not work for Microsoft Dynamics CRM for tablets.

 

Hope this helps!

{Tips &Tricks} Add borders to fields on form in Dynamics CRM 2013

We upgraded recently to Dynamics CRM 2013 and after upgrade one of the feedbacks that came from our customer was that when the form loads for this first time, the fields are clearly not distinguishable. Off course they were talking about the new feature in Dynamics CRM 2013 where the controls are highlighted on the form only when when the field is selected. We tried to make them understand this behavior of CRM 2013 but they were kind of adamant to highlight the fields. Hence we had not option but to resort to the jQuery customizations. The following is the code we wrote on load of the form. We had to choose a different color. However for this blog i have put the code which would highlight the fields with red border.

var attrs = Xrm.Page.data.entity.attributes.get();
for (var i = 0; i < attrs.length; i++) {
var id = attrs[i].getName();
$(“#” + id).find(“.ms-crm-Inline-Value”).css(“border”, “solid 1px red”);
}

Hope this helps!

Dashboard Chart Exporter in Microsoft Dynamics CRM 2013.

Ever faced the requirement where your customer has asked to export the charts in your CRM Dashboard so that they could embed them in their PPTs. Off-course you can ask your customer to enlarge your charts and then take a clip of the chart and save it as file.

I have developed a tool that does all this for you and  little more than that. It shows all the charts you have in the Dashboard in a pop-up window. All you need to do is click on the individual image file and it will then download the charts as image files. And you can use it if you need to embed those charts in your presentation or any word document. Has helped me in couple of scenarios. Hence thought of sharing.

And like all my other tools, it is available for free download at the following codeplex url – https://dashboardchartexporter.codeplex.com/

Please note that this tool works for  Chrome and Firefox (these are the ones I have tested in) but not in IE. Unfortunately IE does not support HTML5 download attribute which this tool utilizes to download the charts as image files.

 

image

 

Hope this helps you!

{Scenarios} – Registering plugins when a user is added to Team in Microsoft Dynamics CRM.

Well if you are reading this topic and thinking that there is already a whole lot of information available on how to register a plugin when a user is added to a team, then why this post again. Yes you are right. But I could see there is some incomplete information in many of the blog posts. So let’s see the complete picture. Many of you might already be aware of this. However still posting because it might be of some help.

 

Ok let’s start then. Say we register a plugin on the AddMembers message for the team entity. Going by SDK documentation, this should fire when we add a user to a team or when a team is assigned to a user. As you can see, I have regsitered a plugin for the AddMembers message for the team entity.

image

However when I manually go ahead and add a member to a team in CRM or when I add a existing team to a user through CRM Application, strangely the plugin does not fire. Search on this and you would find lot of very good blog posts that to handle this, register your plugin in the Associate message as shown in the below screenshot. And in the code handle the primary entity and the related entity.

image

 

Well so far so good and you would have surely come across this if you had ever to register a plugin when a user is added to a team. So does this mean that plugin on “AddMembers” does not fire under any circumstances. That’s not the case. But it fires under a different scenario.

Many a times you need to add a user to a team programmatically using the “AddMembersTeamRequest”. So when this request is executed, the associate message is not fired. instead this time the plugin registered on the “AddMembers” gets fired. Below I have written a code which associates a user to a team.

image

 

Below is the screenshot of what I get in the debugger of the registered plugin.

image

 

So register in the “associate” message when you are adding a user to a team from the CRM application. However if you are adding a user to a team programatically, register a plugin on the AddMembers message because associate won’t fire in that case.

 

Hope this helps!

Exploring Microsoft Dynamics CRM system Js files

For a long time doing this, however thought of sharing this to all you guys. CRM does a lot of whole lot of functionalities using these javascript files.

When do we really need to explore these system files functions. Well as a CRM consultant, frequently i have faced scenarios where the customer is very adamant about a particular requirement which cannot be achieved OOB in CRM using SDK Documented API’s and they are not happy with the workarounds that we provide. Off-course the customer also has a point to stick to their requirements since they also want a system that would most fit their business. Well let’s jump to the solution then.

Well for our example lets take the RibbonActions.js file. A lot of CRM functionalities is done through the ribbons. Well a bit of exploration and you would find that most of the Ribbon functionalities, CRM achieves through the RibbonActions.js file located in <CRM Installation Folder>/CRMWeb/_static/_common/scripts.

When I open that file in the notepad, the following is what the script looks like.

image

Scary right. This is because CRM minifies their javascript files removing line breaks, white spaces etc. which effectively improves performance. Well here our target is to explore the library. For that first let me convert into a more readable format. To do this you will have multiple free jScript formatters available but personally I have always liked the jsBeautifier tool which is available for download from http://jsbeautifier.org/

I copy the contents, paste it in the jsBeautifier tool. Below is the screenshot of what i get after i beautify it.

image

Now it is in much more readable format and as you can see you have all the utility methods the CRM uses internally which you can utilize off if and at all required. Please note that these are system functions and might not work after installing update rollups at any point of time.

Keep a copy of the original file and if you want to explore what parameters are passed when you click a ribbon button, simply replace the contents with the formatted version. You can then even debug these system functions and see what parameters are being passed by CRM to these functions. Do not put a debugger in code. You can simply debug using IE Devloper toolbar or Chrome debugger.

In the screenshot below, I am using the Chrome debugger to explore the CRM system file globalquickcreatebehavior.js

 

image

 

Please note: This article as the name suggests is only for exploring the CRM system js files Do not replace the minified version of js file with the formatted version. CRM minifies the files because of the performance issue. Also tampering the system files might render your application not being supported by Microsoft. At best it can be used for debugging in dev. and for POC purpose. Always maintain a back up of the original file before you replace the contents.

Hope this helps!

Close Quick Create Form in Microsoft Dynamics CRM 2013.

Recently in my project, I came across a requirement where the customer would launch the quick create form and when he clicks on the Save button, our CRM system would perform complex business functions and show a pop-up to the user with a list of available options. If the user selects one of the options from the pop-up, our requirement was to close out the Quick Create form without saving the record.

Our initial guess was to try out the Xrm.Page.ui.close() to close the global quick create form. However that didn’t work.

After quite a bit of exploring the CRM system libraries, finally I could find out a way. CRM uses the .js file GlobalQuickCreateBehavior.js to perform all functions related to Quick Create. The file is located in

<CRM Installation folder>/CRMWeb/_static/_controls/GlobalQuickCreate folder.

 

A little bit of formatting the .js file and voila you have all the wonderful functions that CRM uses for its Quick create Functionality. Just a quick glance below.

Know more on how to open CRM system javascript files in readable format? Checkout my post at this URL – https://debajitcrm.wordpress.com/2014/08/05/exploring-microsoft-dynamics-crm-system-js-file/

image

 

Since this article is all about closing the Quick Create Form, let us quickly explore the function that we need. The following is the screenshot of the function that you can use to close your Quick Create Form.

image

All you need is to call the highlighted function Mscrm.GlobalQuickCreate.GlobalQuickCreateBehavior.closeAllGlobalQuickCreateForms() to close the Quick Create Dialog and you are done.

Please note: this is a system function and any changes done by Microsoft Team in the library would render your code un-usable.

 

Hope this helps!

Call plugin from Javascript in Microsoft Dynamics CRM.

Wanted to share with you all a very interesting way to call plugins from you client side code in Microsoft Dynamics CRM to perform complex operations.Recently in our project  we had a requirement to determine duplicates for an entity based on some very complex business rules with integration from external system. Surely we can call the write some code in a plugin and register it in the pre-validation of Create/ update message of the entity. However our requirement was bit more complex. Not only we had to inform the user of the duplicates but also shown the user, the list of all the duplicates in a webresource popup from where the user can select one of the duplicates. And on top of that all this should be synchronous.

 

So. What can we do? Can’t we leverage the power of server side plugins to write some complex business logic. yes we can. Following is the approach we took.

 

  • 1. We created a entity in CRM which would act as the dummy entity in our purpose. We created a field called ‘new_data’ with type of string which would store the data that we need to pass to server side to process the logic of duplicate detection.
  • Next we create a fetchxml for this dummy entity. Lets say we need to pass account name to the server side to determine the duplicate. So we created a fetchxml in the below format where we are passing the value of account name as a condition for the new_data field.

var fetchString = ‘<fetch version=”1.0″ output-format=”xml-platform” mapping=”logical” distinct=”false”>’ +
                                  ‘<entity name=”new_dummy”>’ +
                                    ‘<attribute name=”new_dummyid” />’ +
                                    ‘<filter type=”and”>’ +
                                      ‘<condition attribute=”statecode” operator=”eq” value=”0″ />’ +
                                      ‘<condition attribute=”new_data” operator=”eq” value=”‘ + accountname+ ‘” />’ +
                                    ‘</filter>’ +
                                  ‘</entity>’ +
                                ‘</fetch>’;

 

  • Register plugin classes in the pre and post of the RetrieveMultiple message for the new_dummy entity.
  • Now we execute this fetch from the client side. To check out how can execute a fetch call from client side in Microsoft Dynamics CRM, please refer to my following blog post – https://debajitcrm.wordpress.com/2014/08/01/how-to-execute-retrievemultiple-request-from-javascript/
  • As soon as you fire this fetch, the plugins registered on the pre and post would be triggerd. The following is the code that I have written in the pre-retrivemultiple of this dummy entity and interecepting the query and taking out the account name from the condition,

var organizationServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            var orgService = organizationServiceFactory.CreateOrganizationService(pluginContext.UserId);

            if (pluginContext.InputParameters[“Query”] is FetchExpression
                && pluginContext.MessageName.Equals(“RetrieveMultiple”, StringComparison.OrdinalIgnoreCase)
                && pluginContext.PrimaryEntityName.Equals(“new_dummy”, StringComparison.OrdinalIgnoreCase)
                && pluginContext.InputParameters.ContainsKey(“Query”))
            {
                var fetchExpression = (FetchExpression)pluginContext.InputParameters[“Query”];
                // Convert the FetchXml to QueryExpression.
                FetchXmlToQueryExpressionRequest req = new FetchXmlToQueryExpressionRequest();
                req.FetchXml = fetchExpression.Query;
                FetchXmlToQueryExpressionResponse resp = (FetchXmlToQueryExpressionResponse)orgService.Execute(req);
                var queryExpression = resp.Query;

               

                foreach (var condition in queryExpression.Criteria.Conditions)
                {
                    if (condition.AttributeName.Equals(“new_data”))
                    {

                       // perform what you need to do here. You can get the value passed in the new_data field using condition.values[0]
                    }
                  

                }

          }

 

  • Wondering how would you pass the data back to the caller client side code. Well that’s fairly easy. In the post of retrievemultiple of the dummy entity, populate the BusinessEntityCollection property of the Entity. Below is the code to do the same. And in the responsexml in your client side you can view the entire data. We parsed the response xml to get the list of duplicates and show it to the user in the webresource.

var organizationServiceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            var pluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            var orgService = organizationServiceFactory.CreateOrganizationService(pluginContext.UserId);

                var entityCollection = new EntityCollection();

                var entity = new Entity(“de_dummy”);
                entity[“new_dummy1”] = // populate whatever you want to return.

                entityCollection.Entities.Add(entity);

                pluginContext.OutputParameters[“BusinessEntityCollection”] = entityCollection;
         

With this approach you can virtually accomplish anything. One more advantage of this approach is you can run these plugins under higher privileged users and perform operation with that user.

Hope this helps!

{Dynamics CRM} How to execute RetrieveMultiple request from Javascript

Frequently in our CRM projects we need to retrieve multiple records for some entity based on some conditions. We have the OrganizationDataService to achieve that. However with the OrganizationDataService we cannot write complex joins and many other stuffs what we can achieve through fetchxml. What if we could utilise the the power of fetchxml from our client side. Well that not difficult at all. Here I would show you how to perform a retrievemultiple request from client side.

Below is the complete code to do the same. Please note that while passing your fetch xml as the request argument, you need to perform HTML encoding of the fetchstring. Otherwise you would get a serialization error when the request is being executed.

var fetchString = [“<fetch version=’1.0′ output-format=’xml-platform’ mapping=’logical’ distinct=’true’>”,
“ <entity name=’systemuser’>”,
    “<filter type=’and’>”,
      “<condition attribute=’isdisabled’ operator=’eq’ value=’0′ />”,
      “<condition attribute=’accessmode’ operator=’ne’ value=’3′ />”,
    “</filter>”,
  “</entity>”,
”</fetch>”].join(“”);

 

retrieveMultiple(fetchString);

function retrieveMultiple(query) {
        var request = getRetrieveMultipleRequestBody(htmlEncode(query));

        return executeRequest(request, false);
    },

function getRetrieveMultipleRequestBody(fetch) {
        var xml = [‘<s:Envelope xmlns:s=”
http://schemas.xmlsoap.org/soap/envelope/”>’,
                  ‘<s:Body>’,
                    ‘<RetrieveMultiple xmlns=”
http://schemas.microsoft.com/xrm/2011/Contracts/Services” xmlns:i=”http://www.w3.org/2001/XMLSchema-instance”>’,
                      ‘<query i:type=”a:FetchExpression” xmlns:a=”
http://schemas.microsoft.com/xrm/2011/Contracts”>’,
                        ‘<a:Query>’,
                            fetch,
                        ‘</a:Query>’,
                      ‘</query>’,
                    ‘</RetrieveMultiple>’,
                  ‘</s:Body>’,
                ‘</s:Envelope>’].join(”);

        return xml;
    };

 

function htmlEncode(str) {
        return String(str)
            .replace(/&/g, ‘&amp;’)
            .replace(/”/g, ‘&quot;’)
            .replace(/’/g, ‘'’)
            .replace(/</g, ‘&lt;’)
            .replace(/>/g, ‘&gt;’);
    },

    // Private function that creates a return object for synchronous calls
function   _getReturnObject(returnValue, successFlag) {
        return {
            Success: successFlag,
            Value: returnValue
        };
    },

    // Private function to parse the error xml.
   function  _getError: function (faultXml) {
        var errorMessage = “Unknown Error (Unable to parse the fault)”;
        if (typeof faultXml == “object”) {
            try {
                var bodyNode = faultXml.firstChild.firstChild;
                //Retrieve the fault node
                for (var i = 0; i < bodyNode.childNodes.length; i++) {
                    var node = bodyNode.childNodes[i];

                    //NOTE: This comparison does not handle the case where the XML namespace changes
                    if (“s:Fault” == node.nodeName) {
                        for (var j = 0; j < node.childNodes.length; j++) {
                            var faultStringNode = node.childNodes[j];
                            if (“faultstring” == faultStringNode.nodeName) {
                                errorMessage = faultStringNode.text || faultStringNode.textContent;
                                break;
                            }
                        }
                        break;
                    }
                }
            }
            catch (e) { }
        }
        return new Error(errorMessage);
    }

 

function executeRequest(request, isAsync) {
        var req = window.ActiveXObject != undefined ? new ActiveXObject(“Microsoft.XMLHTTP”) : new XMLHttpRequest();
        var req = new XMLHttpRequest();
        req.open(“POST”, Xrm.Page.context.getClientUrl() + “/XRMServices/2011/Organization.svc/web”, isAsync);

        // Responses will return XML. It isn’t possible to return JSON.
        req.setRequestHeader(“Accept”, “application/xml, text/xml, */*”);
        req.setRequestHeader(“Content-Type”, “text/xml; charset=utf-8”);
        req.setRequestHeader(“SOAPAction”, “
http://schemas.microsoft.com/xrm/2011/Contracts/Services/IOrganizationService/RetrieveMultiple”);
        req.send(request);

        if (req.status == 200) {
            return _getReturnObject(req.responseXML, true);
        }
        else {
            return _getReturnObject(_getError(req.responseXML), false);
        }
    }

 

Hope this helps!