May
28

Mail Merge in Microsoft Dynamics CRM 4.0 doesn’t sort contacts

Noticed when tested the next CRM rollup.

Consider this scenario:

1. Open Active Contacts view in CRM.

2. Select several contacts (ctrl + click, or shift + click).

image

3. Start mail merge with merging selected records on current page.

image

When we get a list of recipients, it is sorted randomly, as well as resulting letters:

image

Then we are at risk to put wrong letters to envelopes.

Work around? Don’t forget to sort the list of recipients in mail merge dialog box before creating letters. No others’ experience found by now.

Luckily this didn’t happen with merging all contacts from saved Advanced Find views or from marketing lists. This is an advised way of working.

Posted by Viktor Bardadym | Leave your feedback

Oct
06

Minimum Dynamics CRM Permissions

When configuring security roles in Dynamics CRM, a system administrator is situated between Scylla, allowing users things they shouldn’t do, (and, believe me, the users will do it very soon once permitted) and Charybdis, blocking users’ work. And K.I.S.S. advices, like “leave only read permissions just to the entities we use”, or “use only out-of-the-box CRM permissions, or their copies with minimal changes“ may lead the user to one of these beasts.

To perform an action within CRM, the user may need various permissions that don’t necessarily link link with each other, and which are located far away from each other in the user interface Security Roles.
To choose the right permissions you need an understanding of processes within Dynamics CRM.
This post lists the minimal permissions for several important functionalities of Microsoft Dynamics CRM and explains the backgrounds of them.
In general it is advised to test each new security role with an “alter ego” user having this role.

First login


- Business Management – User Settings – Write – User
First login 
Even if you create a 100% read-only user, let him write his user settings. If a user doesn’t have this permission, on the first login he gets an “Insufficient Permissions” error, because CRM cannot set & save his default entity in UI.
If you still have a good reason for blocking users to save their settings (via Tools - Options), you can block this permission. But then you have to follow these steps for every new user:
- assign System Administrator security role to the new user;
- log in as the new user;
- in Tools – Options slect the default enityt for the user(e.g. Accounts) and save user settings;
- log off;
- remove System Administrator security role and assign the actual security roleto the user.
Set default entity
 

Create an Activity


Looks simple: Core Records – Activities – Create – User. After it, the user can create an activity. But when saving, the user gets an error message ”The logged-on user does not have the appropriate security permissions…”. First of all, activities require Append To rights (don’t ask me why). Good enough for tasks.
Letters, faxes, phone calls and e-mails always have another party: a lead, a contact, a user (to send correspondence to your colleagues), and possibly an account. They have to be appended to other entities, so they need Append rights. And recipients’ entities need Append To.
It goes well with all types of activities except appointments. On saving an appointment, the user gets the same error message, followed by “General Failure in Scheduling Engine”. The first error happens because other users will not see the appointment if it is not shared. The second means that all appointments in the CRM have to be checked with the service calendar for availability, even if users don’t use the service calendar directly.
Add Core Records – Activity - Share (at least for business unit, not just for user) and Service management – Search Availability permissions  and get it working: 
Create an activity
Create an activity
Create an activity

Track an Activity in CRM


Was the above adventure enough to track Outlook entities in CRM? Oops, we get ”The logged-on user does not have the appropriate security permissions…” again. Business Management – Sync to Outlook? Right, but not sufficient. You also need Write access to activities.
Track an activity in CRM
Some sources (e.g.
http://social.microsoft.com/Forums/en-US/crmdeployment/thread/3451e18a-4afd-4436-b0b9-8ebd94156f67) refer to the necessity of read access to all of these records: account, contact, lead, user, and queue. The test shows that some of these entities, like account and queue, may be blocked, and the user still can track the activity (possibly changed by a rollup). The entities you select for Read & Append To access will be available in user’s Set Regarding dialog.

Send Mail Merge Letters


The obvious selections are:
- Business management – Mail Merge (from Outlook) and/or Web Mail Merge (from web interface);
- Core Records – Mail Merge Template – Read;
- Core Records – [used recipient entities, e.g. Lead, Account, Contact] – Read;
Send mail merge letters
Then users have to select the recipients in one of the ways:
- Advanced Find: Core Records – Saved View – Read – User, or
- Marketing List: Marketing  – Marketing List – Create – User, or – Read – Business Unit, or
- Quick Campaign: Marketing  – Create Quick Campaign.
They still don’t get Word icon on your workspace? Ah, like monsieur Jourdain didn’t realize that his speech was  prose, we don’t realize that mail merge is an activity. Moreover an activity has to be appended to the entities to which we send the letters. So we have to add the following permissions:
- Core Records – [used recipient entities] – Append To;
- Core Records – Activity – Create, Read, Append – User.
Send mail merge letters

Create Queck Campaign


As well as Mail Merge, Quick Campaign requires permissions to create, write and append activities. Otherwise the Quick Campaign wizard starts looping.

Create Reports with Report Wizard


When a user with custom security role tries to create a new report, he gets Insufficient Permissions error. The security role has all permissions regarding reports, but Report Wizard still doesn’t start. It happens in Microsoft Dynamics CRM 4.0 environments which have been migrated from 3.0.
Create reports with Report Wizard
The problem is that the new security role is missing some permission(s) and the same time the user interface is missing a control to change them. You can create a copy of System Administrator role and make the needed security role by removal of redundant permissions. (luckily “all to nothing” change takes just one click) This witching works like a charm.
There may be other permission issues solved the same way. (I saw a reference but can’t find it anymore)

Conclusion: by preference use (copies of) standard CRM security roles rathen than creating security roles from scratch.
Another advice you can find in literature and on the internet is not to change any predefined roles in the CRM.
Source:
http://www.techtalkz.com/microsoft-dynamics-crm/494850-insufficient-permission-report-wizard-crm4-0-a.html
 

Use Custom Entities


If a new custom entity is created, by default only the system administrator gets access to it. Other users will not see the entity. Even worse, they will not see any related values, lookup fileds in other entities,which use the custom entity. So whenever you create a new custom entity, give permissions to this entity for all security roles which are expected to use it, or any entities related with it. Configure the permissions on Custom Entities tab.

Use custom entities



Run Automatic Workflows


An action taken by the user may start a workflow which will create or update other records. For example, creating an opportunity may start a workflow which creates a follow-up task. Whenever you set up such a workflow, control that the user who may perform the original action cal also run workflows and take actions upon entities affected by the workflow.

Deletion of Records – The Rule and The Exceptions


The last but not the least, and it’s different. You can do anything but lay off of deleting blue suede CRM records.
Block deletion of records for all security roles except for System Administrator. By deleting records users will not only produce orphan records of other types. If a deleted record (like account) has parental relationship with other records, they all will be deleted.
Advise users to deactivate records, or to close activity records instead. One of many advantages is that you get “undo”. You can reactivate lead / customer records. In principle you can reactivate other types as well, but that’s another story.
The action to deactivate records has several reincarnations:
- Cancel (orders, invoices, cases and campaigns);
- Close (activities, opportunities and quotes);
- Convert (leads);
- Unpublish (workflows, duplicate detection rules and knowledge base articles).
And there are still quite some entities which cannot be deactivated:
- E-mails (it’s completed only when it’s sent. To delete an unsent draft, you have to enable deletion for all types of activities);
- Customer Relationships;
- Saved Views (Advanced Find);
- System jobs, like import, duplicate detection,…
- Reports (only revert to personal);
- Competitors;
- Products;
- Sales Literature;
- Quick Campaigns;
- Contracts;
- Announcements;
- Security Roles;
- Teams (neither deleted);
- Facilities/Equipment;
- Subjects.
As exception, deletion of some of them may be permitted for few power users. 
Deletion of records

Still don’t know what to do?


If this post does not cover your situation, or the advises don’t help, go for an advanced action.
- Enable  tracing:
http://support.microsoft.com/kb/907490
- Reproduce the error.
- In trace log search by error code and find the permission GUID:
Error: Server was unable to process request.
Error Number:
0x80040220
Error Message: SecLib::CrmCheckPrivilege failed. Returned hr = -2147220960 on UserId: e65023ae-54d1-da11-8e39-00145e3d5192 and PrivilegeId: a8ecac53-09e8-4a13-b598-8d8c87bc3d33
- Identify the missing permissions by querying the permission GUID in the CRM database, as advised by Microsoft: http://support.microsoft.com/kb/953962.
select Name,  * from PrivilegeBase where PrivilegeId = 'a8ecac53-09e8-4a13-b598-8d8c87bc3d33'
Posted by Viktor Bardadym | 4 Comments

Sep
28

CRM Migration - Migrant’s Notes

When your customer decides that his legacy CRM system is junk, and he has to move all business data to Microsoft Dynamics CRM with your help, he doesn’t expect “junk in - junk out” effect.

What are the critical success factors and the things which need special control during migration of business data to Dynamics CRM? See further – most of them are simple but often overlooked. And missing it may lead to stopping the migration, taking “ad hack” solutions, and making the migrated data even more junk than the original ones.

Good detailed plan

As for any activity with many details and dependencies, make detailed checklist of actions to perform and things to control on preprocessing, migration and postprocessing. Use top-to-bottom approach to plan actions: start with the most general and then bring more details to each level. Identify dependencies and put the actions in correct order.

Preparation on staging environment

Use staging Dynamics CRM environment to prepare the migration. When you (and your customer) are sure that all data are correctly migrated to the staging environment, do the migration to live. Backup & restore of the CRM organization database is not always an option: the restored CRM environment may not start at all. Backup & restore is not applicable at all if staging and live environments (and consequently Active Directory user accounts) are located in different domains.  

Keep the customizations of your staging environment identical to live as much as possible. Do not make parallel customizations in live and staging UI, even if they look identical. After such changes, further export and import of customizations between live and staging may become impossible.

No orphan records

In legacy CRM applications, records may have blank or invalid ID’s of related records. This can crash the software you use (for example, upgrade of ACT! database from an older format before migrating to MS CRM).

If possible, identify and fix or delete orphan records at early stage. In old ACT! and GoldMine databases you can do it on back end in dBase files.

Permissions

Migration tools and SDK’s may require that all users, active and historical, have permissions to create, append, append to, share,… If so, before the migration create all active and historical users in Active Directory and CRM and assign System Administrator role to them. After the migration secure CRM by removal of System Administrator role. Then you can assign all records owned by historical users to  actual  users, and only then disable historical user accounts.

Control size of fields

Control that all field values fit into size limits of CRM fields. Update size limits in CRM if needed. But keep in mind that updating sizes of standard fields (like address1_line1) may not solve the problem. Instead of size limit error, the import job can produce an unspecified server error.

Long values particularly happen in address fields. Consider splitting the address over several fields (address1_name, address1_line1, address1_line2 and address1_line3,…).

If you use standard CRM import, you can still save the refused records “on the fly”, split the long values, and repeat the import for refused records. 

Handling import errors

No special characters in field values

(like line end characters with ASCII codes 10 and 13)

Get rid of them before the import. Otherwise, sooner or later, they will make trouble. For example, if the data are imported from CSV files via standard CRM import, line breaks can break a record line into several, even if text qualifiers are used.

Notepad++ is a good tool to identify them in text files (e. g. CSV).

Control business required values

Control that all business required fields are 100% populated.

Control unexpected intelligence of your tools

If you export data from Excel , or use Excel to process the data, don’t be surprised with telephone numbers like 8.61E+12 or -166.0405405, while the original numbers are 8612345678910 and +32-9/222-99-99. The first one is a rounded “approximate” phone number in scientific format (8.61 x 1012), and the second is a “calculated” phone number (have you ever dialed an approximate negative fractional phone?). Excel doesn’t have cell format for telephone numbers and treats such input as a big numeral in the first case, or as a valid formula in the second case.

Solution: convert such values to text by Excel function TEXT.

Person’s names

Some systems don’t explicitly split contacts’ given names and family names. Foresee the rules which defines given names and family names in Dynamics CRM as adequate as possible.

Take into account that:

  • both given names and family names may be multiple; (e. g. Juan Luis Gonzalez Fernandez)
  • family names may have prepositions, sometimes multiple (e. g. Van Den Bogerd or de la Croix), which have to stay with the names;
  • names may be accompanied by salutations, titles, military ranks  in various languages, sometimes multiple, (e. g. Prof. Dr. Ing. Von Hochenbalken) which have to be separated and saved to a different field;
  • delimiting of the above parts may be inconsistent (space, dot with space, just dot);
  • even if you would have a comprehensive dictionary of given names, in some cultures it’s different to distinct family names from given names; (for example Roger Vincent, Laurence Olivier, Marcu Matei)
  • the field lastname always has to get a non-empty value, since it is business required.

A possible action plan is:

  • prepare the dictionary of “normalized” prepositions and the dictionary of “normalized” titles.
  • prepare the script with the functions which identify and split the full name to its parts based on the most typical name format (e. g. [Titles ]Firstname Lastname). This is possible even in Excel with usage of VBA.

Correctly treat  “All in one” legacy contact records

Many popular contact management applications (Microsoft Outlook among them) use single record for account and contact. Other systems (like ACT! by Sage) allow limited number of multiple contact persons in one database record. The data model of Dynamics CRM is different, it uses single record per account and single record per contact. If you migrate the data from such sources to the CRM, you have to split it to two Dynamics CRM records and later to assign Parent Customer and Primary Contact relationships between them.

For the original records create unique ID’s and migrate these ID’s to both account and contact records. If the data come from multiple sources, indicate the data source in the ID. Upon importing  accounts and  contacts, match them using unique ID’s.

One account may have more than one contact. If you want to eliminate duplicate accounts, at the stage of preprocessing define primary records for obsolete accounts (if the data of accounts are identical, or you have no preferences for the primary account, you can do it automatically in Excel using formulas), and then map contacts to primary accounts. Such updates of CRM records and many other handy thongs may be done by the CRM Bulk Update and Export tool available on Codeplex.

Complete this mapping before the users start manual hunting for duplicates.

Find the best balance for duplicate detection and merge

The right moment to merge duplicates (preprocessing, migration, or postprocessing) depends on how clean the data are. The customer may have an idea that source A is cleaner than source B. If so, import source A first and non-duplicate data from source B next.

In principle, the source B can be imported first, followed by source A and update of the data with available values from the source A. Be careful with updates “per field” (like “take the value form better source if not blank, otherwise take the value from the worse source”). For example, a record from the worse source may have data in two address lines (address1_line1 and address1_line2), while the corresponding record form the better source has only address1_line1. As a result, this rule may give a mixture of lines taken from two different addresses.

If after all the customer realizes that he needs company name from one source, e-mail address from another, and VAT code from the third (like a young lady form a classical comedy who searched a groom with nose of Mr. A., ears of Mr. B, and incomes of Mr. C.). If so, either let the customer to clean the data before the migration, or migrate all data, double and triple, to the CRM. CRM allows you to identify duplicates and to merge two records into one with specific selection of sections, fields from each merged records, or selection of the whole record.

Merge Duplicates

Merge Duplicates

Out-of-the-box duplicate detection in CRM is more than basic, but you can enhance it by using calculated match names. Normalize account or contact names by:

  • converting them to lower case and trimming;
  • converting letters with diacritics to standard Latin letters (e.g. Maïté to maite);
  • removal of texts inside parentheses, like alternative spellings or comments;
  • removal of punctuation marks and special characters (at this stage better to replace punctuation marks with spaces, since they delimit single words);
  • removal of common abbreviations, like English Ltd, German GmbH, or French SPRL;
  • removal of spaces.

The order of the above actions is important.

This matching method was compared with six more sophisticated metrics used to find duplicates (Jaro-Winkler, Jaro, Levenstein, Monge-Elkan, Needleman-Wunch, Smith-Waterman-Gotoh) on the migrated business data. In 95% percent of cases it gave the same or better matches as any other method, and the results, even wrong, were much more obvious for the users. The failures of this method normally had words in different order, like “University of Antwerpen” vs. “Antwerpen University”.

A match name plugin used for duplicate detection can be found on Codeplex.

International challenges

Control that the data prepared to import comply with your language and regional settings:

  • date formats: dd-MM-yyyy vs. MM-dd-yyyy.

For specific types of values in activity records third party migration tools accept only dates in English (US) format. This can make problems if in client's system the regional settings of Windows or CRM are different. If it happens, change system and CRM data formats to English US, and convert all dates in input data to this format.

  • letters with diacritics and non-Latin letters.

Control how your migration tool treats these characters. If you use bulk update tools, verify that their input data have Unicode format.

  • use of languages and geographical names.

In principle each record has to be in the language you want to communicate to the customer. But this makes use names of multilingual countries (like Switzerland or Belgium) inconsistent. As a result, validation scripts for country specific formats (like ones for telephone numbers) become more difficult. Instead, you can normalize country names to standard English names. Keep in mind that even if you use ISO standard, it’s not always a perfect reference. Say, the name “Taiwan, Province of China” advised by ISO 3166-1 is an insult for Taiwanese people.

Dynamics CRM Import.

If speech synthesis is comparable with getting toothpaste out of a tube, speech recognition is like trying to get the toothpaste back in. (Dr. J. Holmes, expert in speech processing)

 

The same is absolutely valid for Dynamics CRM export  and import.

 

Nevertheless, out-of-the-box import can be used to upload contacts from Outlook contact lists exported to Excel. Users can import the data to the CRM by building a data map between the data table in CSV format and the CRM entity attributes, and then by running an import job. Of course, you have to control that

  • all records being imported have all business required values;
  • there are no duplicate records within the import list and between the import list and the CRM (active and inactive);
  • the CSV files have to be really COMMA-separated, since other characters (tab or semicolon) are not accepted in sample files used in manual mapping. 

 

And even after it the import will not help with lookup and picklist attributes, because the export has their values, while the import requires their ID's (GUID's for lookup values, and numeric ID's for picklist values).

 

There is still a way to import the entities with lookup and picklist attributes. (thanks to CRM guru Jim Steiger) Be careful when following it, since any deviation will stop the process.

 

Good log

If you run scripts which change users’ data (for example, normalizes telephone numbers), foresee that the script informs your customers about:

  • all changes done in the system (so that the customer can handle all information he may miss after the cleanup, like the six more phone numbers, or a comment in the same field)

o   what type of record

o   what record

o   old value

o   new value

  • all suspicious data in fields which are left unchanged,
  • all errors happened during processing, with specific error messages,
  • nothing else (like changing assignment of the old value back to the field).

Since log may get long, foresee easy conversion of the log to spreadsheet or database, which will help to filter by specific type of issue, group records by owner, etc.

Good luck!

Posted by Viktor Bardadym | Leave your feedback

Sep
21

Format and validate phonenumbers in Dynamics CRM 4.0 Plugin

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

Posted by Wim De Coninck | Leave your feedback

Sep
08

Improved Duplicate Detection in Dynamics CRM

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.

Posted by Wim De Coninck | Leave your feedback

Sep
08

Synchronizing activities from Dynamics CRM 4.0 to Outlook

The other day we did some research for a client into the synchronization behavior of Dynamics CRM for Outlook specifically when it comes to activities.

Syncing activities like: Tasks, Appointments, Phone Calls and Letters to Outlook is a powerful option in Dynamics CRM but there can be some ambiguity into what’s gets synced where and what happens when you delete items from Outlook that were previously synced to or from CRM.

These are my current activities viewed in the CRM web client.

image

Looking in my Outlook To-Do bar I get a mix of CRM activities and my own Tasks

image

As you can see from the example above not all activities get synced from CRM to Outlook. So which ones do and what is there counterpart in Outlook?

Sync activities to Outlook

  • Tasks
  • Letters
  • Phone calls
  • Fax

→ All get synced as tasks in  Outlook.

  • Email

→ Email after it’s been send gets synced as sent email but before send it doesn’t get synced to Outlook

  • Appointments

→ Appointments get synced to Outlook as meeting in your Calendar.

  • Campaign responses

→ Won’t show up in Outlook.

  • Service activities

→ Service activities show up as meetings in Outlook

Deleting items in Outlook

This is all quite straightforward but when deleting items in Outlook it is not always clear what happens to the activities in CRM. Well the sync behavior is depended on the status of the activity.

  • When an activity is completed CRM it will stay in CRM but it won’t get synced back to Outlook.
  • When deleting an activity that is not yet completed it will delete in Outlook and CRM.

Although it would be nice to have the email activity before send also synced to a task in Outlook the overall behavior is quite nice and keeps your work load from CRM and Outlook thightly together which I think is a real advantage over other CRM systems.

Deleting items in CRM

Again the behavior is depended on the status of the activity.

  • When an activity is completed CRM it will stay in Outlook.
  • When an activity is not yet completed CRM it will be deleted from Outlook as well.

 Some more information Microsoft written about this sync behavior:

http://rc.crm.dynamics.com/rc/regcont/en_us/OP/help/ug_ol_RecordsActivities.htm

Posted by Thijs ter Beek | Leave your feedback

Aug
27

Auto complete text box in Dynamics CRM 4.0

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.
Posted by Wim De Coninck | 1 Comment

May
08

Dynamics CRM4.0: Client-side validation scripts

Everybody who customized CRM in the slightest will know that adding a client side validation script on one or more fields on a form is quite tedious and repetitive work.
 
Therefor we've looked a little bit deeper at the problem here at Orbit One, to be able to serve our customers quicker, better and more reliable.
 
Let me try and scetch the situation in CRM to add 1 field validator. There are a few steps that you need to do.
  1. Open CRM
  2. Goto Settings
  3. Click on the Customization link in the menu (left side)
  4. Select the entity for which you want to validate a field
  5. Click Forms and Views in the new screen (again on the left side)
  6. double click on the Form item
  7. double click on the Field you want to validate
  8. Select the tab Events
  9. Click on the Edit button
  10. Write your validation logic in JavaScript
  11. Do not forget to enable the event with the checkbox above your validation code
  12. Click the OK button
  13. Click the OK button
  14. Click the Save and Close button on top
  15. Click the Actions button on top and select publish.

Steps 7 through 14 are the steps you'll need to do for every field if you do the validations in bulk.

What we do now is the following. We add some code to the OnLoad event of the form as following:

  1. Open CRM
  2. Goto Settings
  3. Click on the Customization link in the menu (left side)
  4. Select the entity for which you want to validate a field
  5. Click Forms and Views in the new screen (again on the left side)
  6. Double click on the Form item
  7. Click on the Forms Properties button on the right side
  8. Click on the Edit button
  9. Write code here:
    var scriptTag = document.createElement("<script src='/Custom/validation.js' type='text/javascript'>" );
    var array = new Array();
    array = document.getElementsByTagName("head");
    array[0].insertAdjacentElement("afterBegin", scriptTag);
  10. Do not forget to enable the event with the checkbox above your validation code
  11. Click the OK button
  12. Click the OK button
  13. Click the Save and Close button on top
  14. Click the Actions button on top and select publish.
Now that we have done this, lets take a look at the validation.js file. It should load every validation we have, so lets start by adding something that will make the onload of document trigger:
var oldOnload = document.onload;
if(oldOnload != undefined && oldOnload != null && typeof(oldOnload) == "function"){
 if(crmForm.crmFormRootElem.value == "contact"){
  document.onload = function(){ oldOnLoad(); contactFormLoad(); }();
 }
} else {
 if(crmForm.crmFormRootElem.value == "contact"){
  document.onload = function(){ contactFormLoad(); }();
 }
}
 
What does this code do ??? Well, the onload function is stored in the oldOnload variable. Then we check if the oldOnload function is actually a defined, if it is not null and that the type is a function. If this is the case there already was an onload function, so we do not want to lose that one. So what happens next is we create a new document.onload function that calls the oldOnLoad and then our own onload function contactFormLoad. If there is not already an onload function for the document we just use our contactFormLoad.
 
The contactFormLoad function looks like this:
function contactFormLoad(){
 overloadOnChange("address1_telephone1", address1_telephone1_onchange);
 overloadOnChange("emailaddress1", emailaddress1_onchange);
 overloadOnChange("websiteurl", websiteurl_onchange);
 
 hookOnSave(contactFormSave);
}
 
As you can make up from the code above, we're going to validate a phonenumber, an email address and a website url.
 
Then we are going to make sure the onsave also gets triggered so all our validation logic is run at the save, just to make sure.
 
The overloadOnChange method: where most of the magic happens.
 
function overloadOnChange(fieldName, newOnChangeFunction){
 if(fieldName == null)
  return;
 var control = crmForm.all[fieldName];
 if (control != null){
  if(typeof(newOnChangeFunction) == "function"){
   if (typeof(control.onchange) == "function"){
    if (control.onchange != null) {
     var oldOnChangeFunction = control.onchange;
     control.onchange = function() { newOnChangeFunction(); oldOnChangeFunction(); };
    } else {
     control.onchange = function(){ newOnChangeFunction(); };
    }
   } else {
    control.onchange = function(){ newOnChangeFunction(); };
   }
  }
 }
}
 
This is a chunck of code that can be found inside CRM itself.
They use this to hook the clientside code to the fields if and only if the event is enabled checkbox is checked.
I don't want to check every checkbox on every field I want to validate. That's way to repetitive. So in the code above we flipped the positions of our new eventhandler and there old eventhandler, so that ours is triggered before theirs.
This seems like good practice to us because that way we can still use the validation out of the box in CRM like everybody does, but we can also use our method... So this is actually only added value. Nothing breaks in the inner workings of CRM.
 
 
And the hookOnSave part is this:
function hookOnSave(onsaveFunction){
 if (crmForm != null) {
  if(typeof(crmForm.onsave) == "function"){
   var oldOnsave = crmForm.onsave;
   if(oldOnsave != null) {
    crmForm.onsave = function(){ onsaveFunction(); oldOnSave(); };
   } else {
    crmForm.onsave = function(){ onsaveFunction(); };
   }
  } else {
   crmForm.onsave = function(){ onsaveFunction(); };
  }
 }
}
 
Again with the old function that's being saved and so forth and so on ... just as in the previous function we'll do our onsave trigger followed by CRM's own onsave.
 
In our onsave method - contactFormSave - we trigger our functions again:
 
function contactFormSave(){
 try{
     TryFireOnChange("address1_telephone1");
     TryFireOnChange("emailaddress1");
     TryFireOnChange("websiteurl");
     event.returnValue = isFormValid();
 }
 catch (e) {
     displayError("crmForm", "onsave", e.description);
 }
}
 
Followed by the TryFireOnChange. This function has been added because we've had a minor issue in migrating the script. One of the fields in our staging environment was missing in the production environment. So when the field you try to validate the field but it doesn't exist then the catch get hit and nothing happens.
 
function TryFireOnChange(fieldName){
 try {
  if(document.crmForm.all[fieldName] != undefined) {
   document.crmForm.all[fieldName].FireOnChange();
  }
 }
 catch (e){}
}
 
I am not going to elaborate on the validation functions itself because this is not really the scope of this post.
 
 
The PRO's to this approach are pretty huge for us:
  • we can migrate the validations from our staging environment to the production environment by just copying one file.
  • we can just edit the file instead of having to click a bunch of times in the CRM web interface
  • we can still do everything through the CRM web interface
  • we can manage the one file in our source control more easily and track everything better.
I hope you enjoyed reading this, and that it makes your work a little bit easier.
 
 
Posted by Wim De Coninck | Leave your feedback

Feb
27

Dynamics CRM 4.0 tool - Bulk update / export to csv

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.

Posted by Wim De Coninck | 29 Comments

Feb
04

New portal www.iec-iab.be has been launched

IAB
 
On February 3rd, 2009 we have proudly launched a new website portal for the Institute of Accountants and Tax Consultants.
 
This large SharePoint portal has a public section and a password protected zone with information for the Institute members and internships.
 
Microsoft Dynamics CRM 4.0 is used as the central members' directory. It's integrated with SharePoint to provide an automated user account and permission management service.
 
Posted by Olivier Mangelschots | Leave your feedback

Contact us - Raas Van Gaverestraat 83, 9000 Gent, Belgium - Tel. +32 (9) 330.15.00 - Privacy Statement - Sitemap - Sign In Developed with Microsoft Office SharePoint Server 2007