You are currently browsing the tag archive for the ‘CRM 4.0’ tag.

When importing data in Dynamics CRM 4.0 there is no client side code triggered, so to make sure you get phonenumbers (or anything else for that matter) in a clean format, you might want to consider creating a plugin that runs server side and generates an import failure to let the customer know some data is not valid in his imports.

This way the user knows when something went wrong and the correct data will still be imported.

To make this plugin work there is the issue of the country prefixes and areacodes that exist. Therefore it is necessary to create two new entities: Country and AreaCode.

The Country entity needs to contains the telephone prefix of that country (eg: belgium = 32, Netherlands = 33 …)

The AreaCode is contains a link to the country entity and contains the phone areacode. (eg: 9 for Ghent, Belgium …)

Ones this data is in CRM we can use it in our plugin through the webservice.

In the end the phonenumbers will be formatted in an outlook compatible format.

eg: +32 (9) 265.74.20

When using the installer inside the project on CodePlex the plugin will be registered for the create and update messages for lead, account and contact.

 

You can find the plugin on CodePlex in our Dynamics CRM 4.0 Plugins project

Why do I need it?

We’ve noticed the CRM Duplicate detection doesn’t allow for much creativity, you can only create Duplicate Detection Rules with the following condition:

  • full string match
  • begins with (number of characters)
  • ends with (number of characters)

The problem with this is that people or companies aren’t always entered in the same format. For instance if you look at our company name we would create the account with the name "Orbit One". Other people might write "Orbit One BVBA" (the bvba part is a type of business entity)
There are some other examples that come to mind:
"Dell NV" vs "Dell"
"HP Belgium" vs "HP"
"Gaëtan" vs "Gaetan"
"François" vs "Francois"
These exceptions will never be caught by the default CRM Duplicate detection.

How can I fix this?

We added the following attributes and filled the with data:

  • on account => new_matchname (contains the accounts name)
  • on contact => new_matchname (contains the contacts first + lastname)
  • on lead => new_matchcontact (contains the leads first+ lastname)
  • on lead => new_matchcompany (contains the lead company name)

The fields are filled with a normalized name. The process is:

  • to lower case and trim.
  • replace special characters (except parenthesis, a-z, 0-9, special characters like éèàç …, and spaces) with empty string.
  • remove everything between the parentheses eg: "HP (was Compaq)" becomes "HP"
  • remove suffixes and prefixes that are type of business entity
  • remove all spaces
  • replace special characters (eg: é > e, à => a, ç => c, ñ => n, …)

Next there need to be some new duplicate detection rules.

  • full string match on new_matchname for contact
  • full string match on new_matchname for account
  • full string match on new_matchcontact for lead (add companyname if needed in your specific cases)

The current implemented type of business entity which will be stripped are:

  • nv
  • sa
  • vzw
  • bvba
  • cvba
  • sarl
  • sprl
  • scrl
  • nvsa
  • bv
  • llc
  • gmbh
  • ltd
  • ag
  • kt
  • og
  • vof
  • cvoa
  • commva
  • commv
  • ebvba
  • ez
  • belgium

Duplicate Detection Jobs

In CRM you can add duplicate detection jobs by going to Settings > Data Management > Duplicate detection jobs

image

Create a new Duplicate detection job for for instance accounts. Make sure you filter on only active records. When you merge a duplicate record the record that isn’t the master record will be placed on inactive. So if you forget this filter you’ll keep getting the same duplicates 😉

Once the job ran, you can see the duplicates entries.

image

What we think is another major pain in the a$$ is that you can only merge 2 records at a time. So not really in bulk… Maybe we will come up with a solution for this later 🙂

 

You can find the Matchname plugin on CodePlex. There is an installer include so that you don’t need to worry about the plugin registration, creating the steps, …. More on this on CodePlex.

We needed a drop down box in our CRM 4.0 environments for a lot of our clients. The data from the drop down should come from within CRM 4.0 to limit the dependencies to other systems.

The cleanest way we found to do this is via an autocomplete textbox which is actually jQuery.  To make it work we needed to get data from CRM through the CRM webservice. We did this with some helper objects that we found athttp://blogs.inetium.com/blogs/azimmer/archive/2009/02/01/crm-4-0-javascript-web-service-helper-objects.aspx. These objects are created to support a .Net like language to connect to the CRM webservice.

The next problem was an autocomplete function in JavaScript. For this we chose the functions from http://www.pengoworks.com/workshop/jquery/autocomplete.htm. We changed these a bit so there is no-more CSS included, because we did not want to load this (since the look and feel of CRM won’t change (for now)) and we don’t want to screw up the CRM classes that are already in place on the form.

How does it stick together?

Finally we needed to write some plumbing code to make it work.

In the onLoad event of the form you’ll need to add the following code:

function load_script (url) 
{ 
    var x = new ActiveXObject("Msxml2.XMLHTTP"); 
    x.open('GET', url, false); x.send(''); 
    eval(x.responseText); 
    var s = x.responseText.split(/\n/); 
    var r = /^function\s*([a-z_]+)/i; 
    for (var i = 0; i < s.length; i++){ 
        var m = r.exec(s[i]); 
        if (m != null) 
            window[m[1]] = eval(m[1]); 
    } 
} 

load_script("/Custom/ISV/jquery-1.3.2.min.js");
var scriptTag1 = document.createElement("<script src='/Custom/ISV/jquery.autocomplete.js' type='text/javascript'>");
var scriptTag2 = document.createElement("<script src='/Custom/ISV/crmHelpers.js' type='text/javascript'>");
var scriptTag3 = document.createElement("<script src='/Custom/ISV/ISVspecific.js' type='text/javascript'>");
var array = new Array();
array = document.getElementsByTagName("head");
array[0].insertAdjacentElement("afterBegin", scriptTag1);
array[0].insertAdjacentElement("afterBegin", scriptTag2);
array[0].insertAdjacentElement("afterBegin", scriptTag3);

As for the creation of the ISVspecific.js script I would like to link to a previous post a wrote on Client-side validation scripts. In that post you can see a way to create a script paste it in CRM without changing code in the events of every field on every form.

The contactFormLoad function from the previous post (Client-side validation scripts):

function contactFormLoad(){
    var zipoptions = {
                        "borderColor" : "#6699CC",
                        "selectedColor" : "#a7cdf0",
                        "background" : "white",
                        "getDataCallback" : GetCountries 
                     };
    $("#address1_country").autocomplete(zipoptions);
    //add you other onchange scripts here
}

The GetCountries which is assigned to getDataCallback is where the CRM service queries are performed. This should be your own implementation. I have prepared some sample code that retrieves countries from a small custom entity called new_country with the attributes new_countryid and new_name.

function GetCountries(partialCountry){
    try{
        var crmService = new CrmService("new_country", LOGICAL_OPERATOR_OR);
        crmService.AddColumn("new_name");
    
        if(partialCountry != null){
            crmService.AddFilterCondition("new_name", partialCountry + "%", CONDITION_OPERATOR_LIKE);
        }
        var result = crmService.Fetch(20);
        
        for(var i in result.Rows)
        {
            var s= "";
            for(var j in result.Rows[i].Columns)
            {
                s += result.Rows[i].Columns[j].Value;
            }
        }
                
        var ar = new Array();
        var i = 0;
        var addvalue = true;
        for (rowsNumber in result.Rows) {
            addvalue = true;
            var newval = result.Rows[rowsNumber].GetValue("new_name");
            for(resultRow in ar) {
                if(ar[resultRow] == newval) {
                    addvalue = false;
                    break;
                }
            }
            if(addvalue){
                ar[i] = newval;
                i++;
            }
        }
        return ar;
    }
    catch(er) {
        alert(er.message);
    }
}

As you can see in the above code block, the function takes one parameter, being the part you typed in the field you need the autocomplete functionality on. Then some fetch xml is generated by the crmHelper objects and the query is executed. This will only get 20 records as specified in the line crmService.Fetch(20).

The crmHelpers.js contains a method called CrmService.prototype.Fetch, which is a reworked version of the CrmService.prototype.RetreiveMultiple from the code of Andrew Zimmer.

If you would like to use the autocomplete function on a lookup field in CRM (yes, that also works :)) you need to add “_ledit” (without the quotes) to the fieldname. Example:

$("#new_countryid_ledit").autocomplete(zipoptions);
 
You can download a complete sample but don’t forget to create the new_country entity if you want to test.

One of our customers recently asked to do an update on their instance of the microsoft CRM 4.0 platform.

The goal was to change the current Country Picklist to a lookup field which points to a new_country entity.

The new_country entity contains a few translations of the countries in different languages like english, dutch and french, and the ISO codes for each country.

Try to update that in CRM 4.0. So we start looking. The first thing I came across was the MSCRM 4.0 Bulk Data Export Tool

This tool allows you to export data generated by an advanced find view to a CSV file which you can later on import in CRM 4.0 trhough an update job. So I started playing around with it.

The major issue for me is that with that tool I couldn’t get the lookup field to be populated. I tried a bunch of different things like “account,E52B43A8-5FC6-4934-A5A3-96B2983EE140” or just the “E52B43A8-5FC6-4934-A5A3-96B2983EE140” but nothing seemed to work.

So I decided to create a new tool that basically does what i want, without creating an import job. Everything is done through the CRM SDK.

A few things I thought are very cool:

  • You can save your connection. We are a hosting company and we have 6 different CRM instances on 3 different servers, so this is quite nice.
  • One of our clients has 15.000+ records in their contacts. Because CRM returns only 5.000 records for each request, I can’t update them all in one go. This was changed by making multiple requests if necessary.
  • Access all the records and all the fields. In the MSCRM 4.0 Bulk Data Export Tool you can only use the tool on Advanced find views. I allow you to use the tool on the main entity. Which is really helpfull in some cases.
  • It allows you to choose the Authentication type. You can connect to CRM with Active Directory, SPLA, Passport (this last one I haven’t been able to test so if anybody has a CRM with passport please let me know)

It is still a work in progress but it does the job quite nice already so try it out.

The CRM Bulk Update / Export Tool

I hope it helps some of you in your daily (or not so daily) tasks. I know it saved a colleague of mine about 80% of his time for only one case, and I consider that a big improvement. 🙂

The beginning

Ok, in the beginning there was nothing. So, let’s start by taking a look at Introduction to Plug-in Development for Microsoft Dynamics CRM 4.0.

From here we can copy paste some sample code into a new class library.

using System;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;

namespace MyPlugins
{
   public class HelloWorldPlugin: IPlugin
   {
      public void Execute(IPluginExecutionContext context)
      {
         // Call the Microsoft Dynamics CRM Web services here or perform
         // some other useful work.
         throw new InvalidPluginExecutionException("Hello world!");
      }
   }
}

 As you notice when you paste the above code, you’ll get missing an assembly reference errors.

If you haven’t already installed the Microsoft Dynamics CRM 4.0 Sdk , please do so now.

Next add the references and your almost good to go. We can build the code (that doesn’t do anything for now, but what the hay)

How do we get the assembly in CRM ???

There are a few steps you’ll need to preform:

  • Make sure the user with which you want to register the plugin in CRM has the proper roles: either the System Administrator role or the System Customizer role are needed.
  • Make sure the user is a Deployment Administrator in the Deployment Manager.
  • Download the Plugin Registration tool.
  • Run the tool on the server of on a location from where you can connect through AD authentication type (active directory) because otherwise it wont work.

Now you should see the Plugin registration tool.

Enter your connection information in the fields below. In Discovery server you can just type your servername. You’ll be prompted for a password when you hit the Connect button. Once you entered your password, you should see one or more CRM instances in the tree. Hit the organisation you want to register the plugin in and click on the connect button.

The tool is now gathering some information about already registered plugins, messages, …

Click on the register button and select the Register new assembly.

Now press the ellips button (…) to browse to your assembly and choose the location you want the assembly to be stored.

I recommend you use the Database as your assembly storage. The reason for this recommendation is quite simple: if you choose another method you’ll manually have to deploy your assembly after adding or updating.

Next select the register selected plugin’s button. You should now see our newly registered assembly in the list. If you click on the + sign in the registered Plugins & … tree you’ll see the HelloWorld plugin. Right click that and select register new step.

We are now createing a ‘trigger’, so that our plugin code gets hit when something happens. Let’s choose after the update of a contact to start. So make the screen look like this:

Plugin Registration Step

When you now try to edit a contact and save it in crm you’ll see an exception that says something like Hello World 🙂

Catch y’all on the flipside