Friday, February 11, 2011

Whole Lotta Love for CRM 2011 Online Plug-ins

This blog post is a Valentine's Day card to the Dynamics CRM 2011 team members who worked on adding plug-in support for Dynamics CRM 2011 Online.

On a recent project, I've been able to add functionality for a client's online instance that would not have been possible in 4.0. Here's just a few of the CRM 2011 Online plug-ins I've been able to roll-out recently:
  • Formula Field Evaluation: When records of certain types are saved, the plug-in calculates dozens of values. It's coded to evaluate the formulas in the correct order in case of dependent values in "downstream" formulas.
  • Auto-Number: Another plug-in we were able to deploy online is one that automatically generates a unique number for various entities. The plug-in uses a custom entity to keep track of the last number used and formatting requirements such as padding the auto-number with zeros. The new transaction support for plug-ins in CRM 2011 help to avoid generating duplicate numbers under heavy system use.
  • Last Activity Date: It was also possible to create a plug-in for CRM 2011 Online that updates a custom "Last Activity Date" field with the date/time when an activity (letter, e-mail, phonecall, etc.) is completed. The plug-in is registered on the various CRM activity types to update Last Activity Date if the "regarding" object is a certain type.
  • Record "Touches": Another plug-in that we've deployed recently is one that tracks when any user opens a record in the UI. The sales manager wanted to know whether any leads and opportunities were sitting too long without being viewed.
Developing these plug-ins without being able to step through the code was not fun (you have to trace-out statements to the UI... can you say "old school"?), but there's enough code samples and decent documentation in the SDK that it wasn't a severe limitation.

So, thanks Microsoft! This is a huge improvement to your online offering.

-Tim

Wednesday, February 9, 2011

Capture CRM 2011 forms with Snagit

Snagit has a feature that can auto-scroll a web page horizontally and/or vertically to capture all content from the page. In order to use this feature with CRM 2011 forms, though, you have to take some extra steps. I've listed the entire process below.
  1. Open the form to capture. For example, to capture the account form, open an existing account record or click New to create a new account.
  2. Right-click in one of the enabled text fields and select the Display Toolbar and Menubar option. Click OK when the prompt appears. This opens the form in a window that exclude the top menubar. Continue the next steps in this new window.
  3. Expand all tabs that are currently closed/hidden.
  4. Press the Snagit hotkey. Click the button at the bottom of the screen (the one with the up/down arrow on it). Snagit will auto-scroll the form down to capture the entire form.
-Tim

Friday, January 28, 2011

CRM 2011 SDK - Set owner of record to inactive user

Can you programmatically set the owner of a record in CRM to an inactive user?  Yes, but see below for more information.

I'm working on a data migration project involving Salesforce.com to Dynamics CRM 2011 Online. The source data includes thousands of records that are assigned to inactive Salesforce.com users. Our client wants to maintain the owners in CRM but also wants the users who are inactive in Salesforce to be inactive in CRM.

That brought up the question: "Can you programmatically set the owner of a record in CRM to an inactive user?". Yes (see sample code below). The only requirement is that each user (systemuser) must have at least one security role assigned, otherwise the CRM proxy service will throw a FaultException with the message "SecLib::RetrievePrivilegeForUser failed - no roles are assigned to user.".

Here's the code I used to test this scenario:
Guid ownerIdForInactiveUser = new Guid("1412c4da-fb2a-e011-8526-1cc1def8ea35");

string accountName = "Tim Test 1";
Entity accountEntity = new Entity("account");
accountEntity["name"] = accountName;
accountEntity.Attributes.Add("ownerid", new EntityReference("systemuser", ownerIdForInactiveUser));
try
{
   crmService.Create(accountEntity);
}
catch (FaultException ex)
{
   Console.WriteLine(ex.ToString());
}
Cheers,
-Tim

Thursday, January 20, 2011

CRM 2011 SDK: WinOpportunityRequest and ArgumentNullException

In several of the Dynamics CRM 2011 SDK sample C# files, you'll see this comment and code line:

// This statement is required to enable early-bound type support.
_serviceProxy.ServiceConfiguration.CurrentServiceEndpoint.Behaviors.Add(new ProxyTypesBehavior());


You might think that if you're writing late-bound code, like I was doing earlier today for a data migration project, that you wouldn't need that line of code. That's true if all you're doing is creating Entity instances, setting attributes, and executing CRUD operations (e.g., _serviceProxy.Update(myEntity)).

What I learned the hard way today is that you need that line of code if you're calling the Execute method for the service proxy with an instance of WinOpportunityRequest, LoseOpportunityRequest, and the other "Request" classes. If you don't run that code then you'll probably run into the ArgumentNullException after invoking Execute on the service proxy.

In hindsight, the "Opportunity" part of the name "WinOpportunityRequest" should've led me to think "maybe that's an early-bound class and therefore I need to set that ProxyTypesBehavior thing I read about". But I was convinced I was operating late-bound only. Apparently not. Another lesson learned.

Wednesday, January 19, 2011

CRM 2011: Running JScript Code Interactively in IE 8

While working on client-side code in Dynamics CRM, it's often faster to write and test the code incrementally within the context of a a "live" form, so that adjustments can be made quickly. Then, once a block of code is working, most of it can be moved to a code library to be further tested in CRM.

This article shows how to run jscript (javascript) code within an account form to format a phone number. The process utilizes the "Run Script" features in the Developer Tools utility that's included with Internet Explorer 8. The code assumes you are working in Dynamics CRM 2011.

Step 1: Load the CRM form upon which you want to run/test JScript code. For this example, load the Account form since the value of the “telephone1” field will be reformatted later in the example.

Step 2: Enter an unformatted phone number in the Main Phone (telephone1) field.  Example: 4255551212

Step 3: In IE, press F12 to load the Developer Tools window.

Step 4: Click Script and then click the Multi Line Mode button.

Step 5: Run the script shown below.
// Reference the main form window (iframe)

var oWindow = document.getElementById("contentIFrame").contentWindow;

// Reference the field with the phone number to format.
var oField = oWindow.Xrm.Page.data.entity.attributes.get("telephone1");

// Remove any non-numeric characters from the field's data.
var sTmp = oField.getValue().replace(/[^0-9]/g, "");

// If the number has a valid length, format the number.
switch (sTmp.length)
{
case "4255551212".length:
  oField.setValue("(" + sTmp.substr(0, 3) + ") " + sTmp.substr(3, 3) + "-" + sTmp.substr(6, 4));
  break;
case "5551212".length:
  oField.setValue(sTmp.substr(0, 3) + "-" + sTmp.substr(3, 4));
  break;
}
Step 6: View the Main Phone field again in the account form. The value should be formatted as (nnn) nnn-nnnn.

Wednesday, December 22, 2010

Show attribute schema names within form editor

Maybe it's just me, but occasionally I find value in viewing attribute schema names in context of a form. This capability was on my wish list for Dynamics CRM 2011 but it didn't make the cut. Fortunately, you can run the JavaScript code I provided below to do just that.

You can execute this script and any other JavaScript code using the built-in "Developer Tools" in IE8 or by using IE WebDeveloper. First, load the form editor view (CRM displays the form editor UI in its own window). Then press Ctrl+N to open the editor in a window that allows you to get to the IE toolbar. Either press F12 (IE 8 only) or use IE WebDeveloper. Run the script in the interactive script window that's provided in each tool.
document.getElementsByClassName = function(cl,doc) {

  var retnode = [];
  var myclass = new RegExp('\\b'+cl+'\\b');
  var elem = doc.getElementsByTagName('*');
  for (var i = 0; i < elem.length; i++) {
    var classes = elem[i].className;
    if (myclass.test(classes)) retnode.push(elem[i]);
  }
  return retnode;
};
var doc = document.getElementById("contentIFrame").contentWindow.document;
var crmFormFields = document.getElementsByClassName("field",doc);
var crmReadOnlyFields = document.getElementsByClassName("rofield",doc);
if (crmReadOnlyFields.length > 0) {
  crmFormFields = crmFormFields.concat(crmReadOnlyFields);
}
var crmFieldId;
var crmFormField;
for (var i = 0; i < crmFormFields.length; i++) {
  crmFormField = crmFormFields[i];
  if (crmFormField.parentNode.parentNode.parentNode.parentNode.name) {
    crmFieldId = crmFormField.parentNode.parentNode.parentNode.parentNode.name;
    crmFormField.innerText = crmFieldId;
    crmFormField.style.color = "#000000";
  }
}
Here's a snapshot of part of the Account form. After running the script, the display name for each attribute is replaced with the schema name.

 

Thursday, October 14, 2010

Party Foul

Oh no! What's this?!?  Failure: contact_activity_parties: Cascade link type 'NoCascade' is invalid for Delete.


I ran into that error today but found a way around it. Here's the scoop.

I fired up a VPC with Dynamics CRM 4.0 Rollup 13 today and added 21 attributes to the Contact entity, which was previously unmodified. I then exported the Contact entity to XML and send the resulting zip file to someone I work with. He has the main VPC and needed some help. Anyway, he attempted to import the Contact entity into another CRM Rollup 13 instance and got the error I mentioned above.

After calling each other crazy and demanding proof that we were both running Rollup 13 (we were... not crazy, but running rollup 13, well maybe both), I exported the Contact entity and immediately re-imported the zip file. Bam! Same error... on the same CRM instance! Grrrrr.

The "solution"?  I removed the node "<EntityRelationship Name="contact_activity_parties">" from the Contact XML, saved the file, and wouldn't you know it, CRM imported that version of the customizations file just fine.

I'm sure, I have to believe, okay I hope (but not holding my breath) that Microsoft has made customization import/export rock solid between rollups in Dynamics CRM 2011. I can understand that moving customizations between different rollups is hard for Microsoft to get right but exporting and re-importing on the same server, within only 38 seconds lapsing between the time the zip file plopped onto C: to when I optimistically clicked the Import button -- for that not to work is, well, causing me to write this blog post instead of working. So with that, onward to the next challenge.