Advertisements

{dynamics crm clone record} Using Xrm.Utility.openEntityForm to clone all fields of one record to another in Dynamics CRM.

Looking at the title of the topic, you must be wondering what’s new in here. I think many of us by this time already know that we can clone one record of an entity to create another record easily using the  Xrm.Utility.openEntityForm method. For e.g suppose we have an account record and we have a functionality provided to clone the account record. The cloned record would contain the same values and the parent record.

To do this in CRM, all you need to do is the following.

var parameters = {};
parameters["name"] = "Test";
parameters["telephone1"] = "(425) 555-1234";
Xrm.Utility.openEntityForm("account", null, parameters);
 

Now comes the big question. Although its pretty simple to copy field values from one record to another using the above method, imagine of a situation where there are lot of fields on the form to clone. Even for that matter there can be situations where the field is not even in the form of the parent record but you would still need to copy it to the clone record. What’s the solution in that case?

Well as they say Old is Gold. Remember the _CreateFromId and _CreateFromType parameters that we used to clone a record in our early CRM 2011 days. You can use the same stuff in CRM 2013/ 2015 also. The following is the code to copy all the values from the parent account record to the cloned account record.

var accountId = Xrm.Page.data.entity.getId();

accountId = accountId.replace(‘{‘, ”).replace(‘}’, ”);

var parameters = {};

parameters["_CreateFromId"] = "{" + accountId + "}"; // Guid of the record from which values would be copied

parameters["_CreateFromType"] = "1"; // objecttypecode of the record

parameters["etc"] = "1"; // cloned entity objecttypecode

parameters["pagetype"] = "entityrecord";

Xrm.Utility.openEntityForm(Xrm.Page.data.entity.getEntityName(), null, parameters);

And voila! You are presented with a new form with all the values copied from the parent record.

Hope this helps!

Advertisements

Microsoft Dynamics CRM Error Dialog – using Xrm.Internal.openErrorDialog

By this time many of you might have already explored the Xrm.Internal namespace and displayed your custom webresources in CRM 2013/ 2015 modal style. Well, if you have not, I suggest you check my blog post https://debajitcrm.wordpress.com/2014/04/29/exploring-the-xrm-internal-namespace-in-crm-2013/ to explore the Xrm.Internal namespace and i bet you would like it.

Coming back to the topic, if we open our custom webresources in CRM modal style, why not show the custom client side errors in CRM 2013 style? If you are thinking how to to do this, you have to come back to Xrm.Internal namespace and explore its Xrm.Internal.openErrorDialog method.

First let us explore the Xrm.Internal.openErrorDialog method. The following is the nomenclature of this method.

function (errorCode,message,serializedException){var $v_0="0x"+(errorCode<0?4294967295+errorCode+1:errorCode).toString(16).toUpperCase();if(IsNull(serializedException))openErrorDlg($v_0,message,null,0,0);else openErrorDlgWithDetailedInfo($v_0,message,serializedException,0,0)}

So we can see that it accepts three parameters

  • Error Code
  • Message
  • Serialized Exception

Error Code : If you see the nomenclature, it appends “0x” to the error code. It should be a number. If you enter anything other than integer, the method might not work as expected.

Message: I have tried multiple combinations but whatever i entered does not reflect. However if anybody reading this can explore this, it would be extremely beneficial.

Serialized Exception: This is the most important parameter. Whatever value you put here is the one that would come when the user clicks on “Download Log file” button.

As an example, in the account form load, I have called the method as shown in the screenshot below.

image

 

Now when the form loads, the following error message is displayed. When the user clicks on ‘Download Log File’ you can see the Downloaded error message.

image

Hope this helps!

{Dynamics CRM} Create a view in Dynamics CRM that shows UNION of results

Recently we had a requirement where we needed to create a view in Dynamics CRM that shows a UNION of results. To explain it in a more detailed way, let me explain the scenario.

We had a custom entity called Opportunity group and under Opportunity Group we had multiple opportunities. Opportunity entity had four custom fields 1) Sales Person 1, 2) sales person 2, 3) sales person 3 and 4) sales person 4 which are all user lookups.

The customer wanted a view called “My Opportunity Groups” which would show the following

<Opportunity groups owned by the current user>

OR

<Opportunity groups which has opportunities which are owned by the current user or the user is in Sales Person 1 or Sales Person 2 or Sales Person 3 or Sales Person 4>

From the requirement itself, you can easily understand that this is a very simple SQL UNION query. Being a CRM consultant we are not that lucky in that respect since we don’t have the full power of SQL in our hands. So the following questions started arising.

First question – Is it possible through CRM UI? The answer is No because CRM UI does not give you an option with link entities to perform a UNION of results.

Second question – Is it possible through FetchXml? The answer is – if you are using CRM 2013 and above it is possible. Although a bit complex but we finally could put it together. We tested this through SDK and it was fetching the correct results. But had to say, not very efficient performance wise. Please find the fetchxml below for this requirement.

<fetch version=’1.0′ output-format=’xml-platform’ mapping=’logical’ distinct=’true’>
  <entity name=’new_opportunitygroup’>
    <link-entity name=’opportunity’ from=’new_opportunitygroupid’ to=’new_opportunitygroupid’ link-type=’outer’ alias=’an’>
      <attribute name=’new_person1′ />
      <attribute name=’new_person2′ />
      <attribute name=’new_person3′ />
      <attribute name=’new_person4′ />
      <attribute name=’ownerid’ />
      <filter type=’and’>
        <filter type=’or’>
          <condition attribute=’ownerid’ operator=’eq-userid’ />
          <filter type=’or’>
            <condition attribute=’new_person1′ operator=’eq-userid’ />
            <condition attribute=’new_person2′ operator=’eq-userid’ />
            <condition attribute=’new_person3′ operator=’eq-userid’ />
            <condition attribute=’new_person4′ operator=’eq-userid’ />
          </filter>
        </filter>
      </filter>
    </link-entity>
    <link-entity name=’systemuser’ from=’systemuserid’ to=’owninguser’ alias=’ao’ link-type=’outer’>
      <attribute name=’systemuserid’ />
      <filter type=’and’>
        <condition attribute=’systemuserid’ operator=’eq-userid’ />
      </filter>
    </link-entity>
 
  <filter operator=’and’>
      <filter type=’or’>
        <condition entityname=’ao’ attribute=’systemuserid’ operator=’eq-userid’ />
        <filter type=’or’>
          <condition entityname=’an’ attribute=’ownerid’ operator=’eq-userid’ />
          <filter type=’or’>
            <condition entityname=’an’ attribute=’new_person1′ operator=’eq-userid’ />
            <condition entityname=’an’ attribute=’new_person2′ operator=’eq-userid’ />
            <condition entityname=’an’ attribute=’new_person3′ operator=’eq-userid’ />
            <condition entityname=’an’ attribute=’new_person4′ operator=’eq-userid’ />
          </filter>
        </filter>
      </filter>
    </filter>
  </entity>
</fetch>

The trick is in the portion of the fetchxml in red. With 2013 onwards you can write queries in fetchxml similar to left join with a where clause in SQL. Check out my following blog post for more details.https://debajitcrm.wordpress.com/2014/08/27/left-join-with-not-in-operator-in-microsoft-dynamics-crm-2013/

So now the last question. How to put this fetchxml in the view? One solution is to directly go the database and change the fetchxml of the My Opportunity Groups view. Other solution would be register a plugin on the pre-operation of retrievemultiple message of savedquery and for this view, specifically we change the change the fetchxml at runtime. However we did not go by any of the mentioned ways because first of all direct changes in the database is something we were trying to avoid. The other option with plugins would not be very performance effective since it would trigger on the retrieve of every saved view.

Instead we developed an utility to update the fetchxml of the saved query. The following is the code.

var orgServiceProxy = GetService();

var query = new QueryExpression("savedquery");
query.Criteria.AddCondition("name", ConditionOperator.Equal, "My Opportunity Groups");
query.Criteria.AddCondition("returnedtypecode", ConditionOperator.Equal, "new_opportunitygroup");
var savedQueryCollection = orgServiceProxy.RetrieveMultiple(query);

if (savedQueryCollection.Entities.Count > default(int))
{
      var savedQuery = savedQueryCollection.Entities.First();

      savedQuery["fetchxml"] = fetchExpression;

      orgServiceProxy.Update(savedQuery);
}

 

You have to write the GetService Method on your own to fetch the Organizationservice instance.

One catch of this implementation is that you wont be able to edit this view through CRM UI.

Hope this helps!

{Dynamics CRM Error} Error in Microsoft Dynamics CRM email router – Could not verify the version of Microsoft Dynamics CRM.The requested organization service could not be activated.

Recently we started noticing this error in the event log  for Microsoft Dynamics CRM Email Router. After a bit of research, we found that the issue was occurring because from the authentication providers, of Microsoft Dynamics CRM website, the Negotiate provider was removed. So we had to add the Negotiate provider back. The following are the steps we followed.

  • Login to Microsoft Dynamics CRM Application server
  • Open IIS and go to Microsoft Dynamics CRM website
  • Double click Authentication, select windows authentication and Providers.
  • Add the Negotiate provider back.

Please check the screenshot below.

image

Now the big question. Why removing Negotiate causes this error? The reason for this error is because Dynamics CRM Email router tries to connect to Microsoft Dynamics CRM Organization Service using the WebHttpBinding which does not support NTLM with anonymous authentication.

Off course there can be other reasons for this error, but if you have Negotiate removed from the list of authentication providers, doing the above would help to fix the issue.

Hope this helps!

Displaying On Demand Workflows in sorted order in Dynamics CRM 2013

Recently we had a requirement where we needed to display a specific set of on demand workflows in a specific order for a particular entity. Well is this possible? In a supported way? The answer is No. However if your customer is hell bent on this, you can try the below unsupported approach. This solution is only applicable to on-premise environments.

Go to CRM database and pull out the fetchxml for the saved query with name = “On demand Workflows”

select savedqueryid, fetchxml from savedquery where name = ‘On demand workflows’

The following is the fetchxml you would receive.

<fetch version=’1.0′ mapping=’logical’>
  <entity name=’workflow’>
    <attribute name=’workflowid’ />
    <attribute name=’name’ />
    <attribute name=’category’ />
    <attribute name=’createdon’ />
    <attribute name=’modifiedon’ />
    <attribute name=’statecode’ />
    <attribute name=’owningbusinessunit’ />
    <attribute name=’ownerid’ />
    <filter type=’and’>
      <condition attribute=’type’ operator=’eq’ value=’1′ />
      <condition attribute=’ondemand’ operator=’eq’ value=’true’ />
      <condition attribute=’statecode’ operator=’eq’ value=’1′ />
      <filter type=’or’>
        <condition attribute=’category’ operator=’eq’ value=’0′ />
      </filter>
    </filter>
  </entity>
</fetch>

Many of you might have already guessed that this fetchxml needs to be updated with a sort order. However on which column do we need a sort. Well this depends on the requirement. If you need to sort it alphabetically, then you should sort on the name. But if you need to display it some other specific order, here is trick.

Deactivate the workflows and re-activate the workflows in the sequence you wish to display them. Then add the following sort order.

<order descending=’false’ attribute=’modifiedon’ />

The final fetchxml would look like this.

<fetch version=’1.0′ mapping=’logical’>
  <entity name=’workflow’>
    <attribute name=’workflowid’ />
    <attribute name=’name’ />
    <attribute name=’category’ />
    <attribute name=’createdon’ />
    <attribute name=’modifiedon’ />
    <attribute name=’statecode’ />
    <attribute name=’owningbusinessunit’ />
    <attribute name=’ownerid’ />
    <order descending=’false’ attribute=’modifiedon’ />
    <filter type=’and’>
      <condition attribute=’type’ operator=’eq’ value=’1′ />
      <condition attribute=’ondemand’ operator=’eq’ value=’true’ />
      <condition attribute=’statecode’ operator=’eq’ value=’1′ />
      <filter type=’or’>
        <condition attribute=’category’ operator=’eq’ value=’0′ />
      </filter>
    </filter>
  </entity>
</fetch>

Update the fetchxml of the saved query. And voila! you are done.

Hope this helps!

{Dynamics CRM Fix} Idiosyncrasies while dealing with Business Process flows in CRM 2013/ 2015.

Looking at the title of the topic, you must be thinking that I am going to discuss any bug in Business process flows. Well not exactly. However there are some situations where using business process flows can lead to confusing errors. Lets see such an example.

Let’s say you have a requirement where progression from one stage to another is dependent on some other factors. When the user tries to move to the next stage, there is some plugin or synchronous workflow which validates and throws a business process error. However when the user fixes the issues and tries to save the form, he keeps on getting the business process error although now all the entered values are correct. I have created a very simple set-up to simulate the situation.

In the example below, Stage 1 in the contact form has a Company field which needs to be filled if the user wants to move to Stage 2. I have created a synchronous workflow which throws a business process error if the user tries to change the stage without filling in the company field. Please check for the screenshots below.

image

 

image

 

Now without entering the company, we save the record and the contact is saved successfully.

Without the company name still not entered, Next stage button is clicked and as expected we get the following Business Process error.

image

Now even if we change something and try to save the record, we would keep getting this error. Why does this happen. Let’s explore.

When the form was saved for the first time, let’s query for the stageid field.

image

After we get the error, lets check for stageid on the form.

image

So as you can see, even though the record was not saved, the stage id field is holding the guid of the next stage and is in dirty stage.

So when you click save, this new stage id gets passed to the platform and hence we keep on getting the error.

So the solution to resolve this problem is to set the stageid back to the initial value when the form is about to be saved.

 

Hope this helps!

Reload an entity form in Dynamics CRM 2013/ 2015

From CRM 2013 onwards, many a times we need to reload an entity form since from CRM 2013 after saving of the record, the entire page does not refresh. And frequently to do this, I have come across use of window.location.reload method to do the same.

Off course there are ways to asynchronously update the data section or the ribbon section using the Xrm.Page.data.refresh(true|false) and Xrm.Page.ui.refreshRibbon() respectively. But if at all, your intention is to reload the entire form, you can do so using the Xrm.Utility.openEntityForm method.

In the section where you need to reload the page, call the above method. For example -  to reload an account record use the following code.

Xrm.Utility.openEntityForm(“account”, Xrm.Page.data.entity.getId());

Hope this helps!