Archive for Customization

Many-to-Many Relationships

In life, many-to-many relationships are recipes for pandemics. In Dynamics CRM they aren’t quite as bad, but they can be confusing until you get used to them. This article is about the Dynamics CRM variety, but if you want to read a chilling description of the real-life kind, here’s a link to Larry Brilliant’s article, The Age of Pandemics.

Background: One-to-Many Relationships

The most frequently encountered relationships between Dynamics CRM records are “one-to-many”, often referred to in shorthand as “1:N”. On any Dynamics CRM form, these are exposed as the links you see on the left-hand side. Basically, every link you see there is a record type to which the record on the form has a 1:N relationship. For example, the following figure shows an account form with the Contacts link selected. This displays all of the contact records which are related (via the “Parent Customer” lookup field on the Contact form) to the current account record

.

Before moving on to many-to-many relationships, let’s examine 1:N’s from a different perspective. Look at the next figure. It shows the flip side of the 1:N from account to contact. That is, it shows an N:1 from contact to account:

This shows how it looks from the standpoint of the “child” record. In this example, there can be multiple contact records associated with one account record, so on the contact form the account (”Parent Customer”) is selected with a lookup, from which only one account record can be selected. If you wanted one contact to be able to have multiple parent accounts, the simple 1:N from account to contact won’t let you do that. That’s an example of where you’d need a “many-to-many”.

Many-to-Many Relationships

One-to-many (1:N) relationships are common, but there are plenty of situations that require a many-to-many (”N:N”) relationship. For example, a single contact might attend one or more events; and a single event might have multiple attendees. In my experience, N:N relationships are more common than you might at first think, and there are some subtleties about how they’re implemented in Dynamics CRM. Let’s look at a few examples.

A commonly requested customization is to make the relationship between records and “Owners” more flexible. Most records in Dynamics CRM are so-called “user owned” records, which simply means that each one is associated with a single user — the “Owner” you can see an example of in the following screenshot of an Opportunity form:

Comparing this to the previous figure, you can see there’s an N:1 relationship from Opportunity to User (referred to as “Owner” on the form), which is equivalent to saying there’s a 1:N from User to Opportunity.

In this scenario, the request might be to associate more than one user with an opportunity. For example, you might have an account manager, an executive sponsor, and a sales engineer, each with certain required tasks in the sales process. Suppose you knew for sure that those three roles were the only ones you needed. In that case, you could create two new custom 1:N relationships from User to Opportunity, and add the associated lookup fields to the opportunity form:

I only had to add two, since the “Owner” was already there, and I just changed the label on the form to “Account Manager”. This works fine, but it’s hard-wired to only three users per record. What if you don’t know how many different users might need to be associated with a record? That’s a job for a true N:N relationship. The following figure shows how this can look. I’ve created a custom N:N relationship between Opportunity and User, and I referred to it as “Stakeholder”. The screenshot shows an opportunity form open with the “Stakeholders” link selected.

This looks similar to the very first screenshot in the section on 1:N’s, but it’s different in an important respect: with an N:N relationship both sides of the relationship behave exactly the same. In this example, that means that if you open a user record you can see all the opportunities for which the user is a stakeholder:

So, not only can each opportunity be associated with lots of stakeholders, each stakeholder (a.k.a. “User”) can be associated with lots of opportunities: a true N:N relationship.

To create an N:N like the one I just illustrated, assuming you’ve got System Administrator privileges, follow these steps:

  1. Open the Opportunity form’s customization UI, by clicking Settings, Customization, Customize Entities, and then double-clicking Opportunities in the list.
  2. Click N:N Relationships, then click the New Many-to-Many Relationship button on the toolbar.
  3. Select User in the “Other Entity” section, and configure the other properties like this:

Then click Save and Close twice, then publish and test your customizations.

Just remember: the value in the “label” field is how the entity in each section will be referred to from the form for the other entity. This can be confusing, and it’s probably easiest to start by using the default “Use Plural Name” option in the Display Option drop-down.

Limitations and Subtleties of “Native” N:N Relationships

The approach I just described is often referred to as a “native” many-to-many relationship. It’s a new feature in the current version of Dynamics CRM, and can be used instead of the alternative, the so-called “manual” approach. The manual approach is not new, by the way, and simply consists of two 1:N relationships. For example, I implement N:N relationships between contacts and events by creating 1:N relationships from each of those two to a third entity, “registration”. A 1:N from contact to registration, and a 1:N from event to registration gives me an N:N between contact and event.

These native N:N relationships are easy to create, but have at least one important limitation, and some subtleties that can be confusing at first. I’ll cover those here.

  • Limitation #1: All you know is whether a relationship exists – you don’t know anything about the relationship. The easiest way to understand this is to think about the manual N:N I just described. With that approach, the third entity – often referred to as the “junction” or “intersection” entity – can contain useful information. If I want to know the status of a registration, or what the registration fee was, then the manual approach works better.
  • Limitation #2: While you can use Advanced Find to query for which records are involved in an N:N relationship, you cannot add columns from the opposite side. Basically, the problem here is that Advanced Find doesn’t really work for native N:N relationships. The way I think of it is that with Advanced Find, you start at the level of the child (or “N”) record, and work your way back up. So if I want to do a query on opportunities and return in the result set lots of information from account records, I have to start with opportunities. But if two entities are related with a native N:N relationship, there is no parent or child entity, both entities being peers, and without a 1:N relationship, Advanced Find doesn’t work!

Limitation #2 is actually more general than the Advanced Find example I illustrated with. What else in Dynamics CRM depends on 1:N relationships and makes you start at the child record and work your way back up? Correct: Workflows!

Hence the following question from a very patient TrickBag reader:

I recently created a custom entity (Network Event)that has a N:N relationship to Contact. What I’m trying to do is identify Network Events at which I meet contacts (new and existing).  So for any Network Event there may be several Contacts, and for any Contact there may be several Network Events.  I used the native N:N relationship, and it works just as I want it to.


What I am having a problem with is creating a Workflow that will update two custom fields on the Contact record to show the date of the event and the name of the event.  I’m just trying to indicate the last activity with my Contacts.  I’ve been successful in creating workflows for Tasks, E-mail, Appointments, etc. that update the two custom fields on the Contact record.


When I try to create A Workflow from the Network Event that will update the Contact record, the Contact is not an option as a Related Entity.  What am I missing?

 

Stephen, I’m sorry it took me so long to answer, and I’m sure you know this by now, but the answer is you aren’t missing anything except that intersection entity I mentioned above. Neither Advanced Find nor Workflows gives you a handle to columns from entities on the other side of a native N:N relationship. That’s why you could do it for your Task, E-Mail and Appointment activities: they all have N:1 relationships to contacts. But the way you modeled your contacts and networking events won’t work for that. Try creating a third entity, “Networking Event Attendance”, and give it fields for the date and name of the event. Then, when you write your workflow on the Networking Event Attendance entity, it will work fine.

And in Conclusion…

Well, this article certainly turned out longer than I thought it was going to be when I started it. I guess if you’ve read this far, you’re really committed, so I’ll make two more observations:

  1. Although Advanced Find doesn’t work with the native N:N approach, the Report Wizard does work. In the opportunity to user/stakeholder N:N example I used, you can create a report with Opportunities as the parent record type and “Stakeholders” as the related record type, and you can group on opportunity, displaying within each group one row for every stakeholder.
  2. Another good example of where an N:N relationship comes in handy has to do with synchronizing records to the Dynamics CRM Outlook client. Suppose you and your users want to synchronize records locally (Local Data Groups, in the Outlook client), and you can’t come up with any convenient criteria to use. You might put a checkbox on a form that’s a Yes/No to synchronize…but the problem with that is if it’s selected and used to synchronize…it synchs for everybody! A good solution here is to create a native N:N between the entity in question and the User entity. Call it “Synching Users” or something like that, and let users add themselves as a “synching user” for any record they need to synch. It works great.

If you read this far I’m eternally grateful, not to mention impressed with your dedication. Thank you very much, and good luck with all your relationships, Dynamics CRM and otherwise.

P.S., if you liked this article, you will positively adore my upcoming Dynamics CRM Essentials sessions, especially the ones on Customization. I hope to see you in an upcoming session!

Leave a Comment

Essential Links, Downloads and Resources

 Here’s my short list of “essential” links, downloads and various resources for Dynamics CRM 4.0 and Dynamics CRM Online. I hope you find it useful, and let me know if I missed any of your essentials.

Links, downloads and other resources

Dynamics CRM 4.0 SDK The single best reference for customizing and extending Dynamics CRM.
Dynamics CRM 4.0 Implementation Guide The single best reference for installing and deploying Dynamics CRM on-premise, and in particular the single best piece of documentation if you’re preparing for the MB2-633 Installation and Deployment exam.
   
Logical Database Diagrams Deep drill-down on how all the out of the box entities related to one another.
Microsoft Dynamics CRM 4.0: 90-Day Trial Versions of software Download the bits, install them with supplied product keys, and use them for 90 days.
Dynamics CRM Developer Center The uber-spot for Dynamics CRM developers. There are a lot more useful links there than I have in this article…but in case you forget that link and remember this one, I include it here.

Add-on programs and applications

 
 
 

 

Once you get Dynamics CRM up and running (install it, for the on-premise version; walk through the setup wizard for Online), there are a number of optional add-on programs you may want to use. These are all free (they won’t do you much good if you don’t have Dynamics CRM!), and they do not need to run on the Dynamics CRM server machine. The “big three” in my opinion are the E-Mail Router, the Outlook Client, and the Data Migration Manager. Important point: notice that each one of these has a different downloadable, depending on which version of Dynamics CRM you’re running. A lot of people don’t realize this, since the functionality is identical, but it’s important to use the right version.
Dynamics CRM E-mail Router:

This gives you centralized management of integrated e-mail. It works with any e-mail server application as long as it supports POP3.
Dynamics CRM for Microsoft Office Outlook (the “Outlook Client”)

The Outlook Client provides two main functions:

  • The main reason to use it is that it’s awesome. It makes “doing CRM” a simple extension of Outlook.
  • Also: if you don’t use the E-mail Router, you can still have integrated e-mail by using the Outlook Client. It’s not centralized, but it’s easy.
Dynamics CRM Data Migration Manager:

The Data Migration Manager allows you to migrate relational data sets in one pass, create custom entities on the fly, and a number of other features that the
Dynamics CRM 4.0 Language Packs
  1. Download one of these and install it on your CRM server.
  2. As a system administrator, “enable” the installed language in Dynamics CRM.
  3. Then your users can toggle the CRM UI and Help between the base language and anything you’ve installed and enabled. Sweet!
Dynamics CRM 4.0 Sample Data Set The pre-configured AdventureWorks data set, all ready for importing after you install the Data Migration Manager.
Demonstration Tools for CRM 4.0 This cool set of tools lets you do things like create sample data, perform a find and replace to rename an entity, and some other good time-savers.
Accelerators for Microsoft Dynamics CRM
 Here are the three new ones:

NEW
Social Networking
NEW
Portal Integration
NEW
Partner Relationship Management 

 

 
Here are the rest:
Notifications
Event Management
Extended Sales Forecasting
eService
Analytics R2
Enterprise Search R1
Business Productivity Newsfeed
Business Productivity Workflow Tools
Business Data Auditing
Sales Performance International (SPI) Sales Methodology

 

The Accelerators for Dynamics CRM 4.0 are essentially reference applications that run on top of and extend the core Dynamics CRM platform. Most of them are horizontal, adding functionality that might be used by any organization, such as auditing, enhanced analytics, and so forth.
 All of the Accelerators require the installation of software on your Dynamics CRM server machine, and so they all require the on-premise version of Dynamics CRM.
 As of Dec. 5 2009 there are 13 accelerators available. At the left I provide links to the overall landing page, the three newest ones (the social networking one integrates Twitter and Dynamics CRM), and the rest of them.
 
 All CodePlex Dynamics CRM Projects CodePlex is an awesome resource: open source (free, downloadable) code you can run on top of Dynamics CRM.

Comments (1)

Internet Explorer Tab Sets and Windows Scripting Host

Launch IE with your Favorite Groups of Sites

In another article I discussed a commonly used trick that lets you navigate directly to certain Dynamics CRM windows, and showed how to combine that with IE tab sets to build an efficient, dashboard-style user experience for Dynamics CRM.

In that article I used my organization’s Dynamics CRM Online to illustrate. The technique is identical whether you’re using CRM Online or on-premise, but it might be more useful in Dynamics CRM Online, because more functionality is exposed through this direct navigation technique. For example, the November 2009 Service Update added the sweet new home-page dashboard with customizable charts, so I now use a URL like this one — https://imginc.crm.dynamics.com/Home/Homepage/TTV_Home.aspx — to navigate directly to a page like this one:

 

When you’ve got a hammer…

…everything looks like a nail, right? So of course, I created a bunch of tab sets for the various groupings of web sites I tend to go to on a regular basis. A few minutes later, I’d created four tab sets (which are really just IE favorites folders), with four or five sites in each. This was a useful exercise, as it made me think about how the different web sites I use work together to support the activities I’m doing. Here’s a shot of what my favorites folders/tab sets look like, with a summary of how to use them:

Use Windows Script Host to open in different IE Windows

As soon as I started using them, however, the tabs quickly got out of hand. For example, if I open my Dynamics CRM tab set that’s four tabs, then I open my blogs and add six more tabs…and it’s just as easy to lose track of things as ever.

What I really needed was to launch IE and have it open a single tab set in a separate window. After hunting around a little bit, I found this nice summary of how to use COM automation to do this, using the Windows Scripting Host to automate Internet Explorer: http://blogs.msdn.com/tonyschr/archive/2007/01/19/ie-automation-amp-tabs.aspx

I’ve never done much with Windows Scripting, but it was exactly what I needed to solve this problem. If you run wscript.exe from the command line it doesn’t really do anything; the key is to provide a .js file as a command line argument. Here’s the file I created (copying Tony’s example from the article above) that opens up all of the pages in my Dynamics CRM dashboard, each on a different tab in the same window. The following script is in a text file I called “crmsites.js”:

var navOpenInBackgroundTab = 0×1000;

var oIE = new ActiveXObject(“InternetExplorer.Application”);

oIE.Navigate2(“https://imginc.crm.dynamics.com/loader.aspx”);

oIE.Navigate2(“https://imginc.crm.dynamics.com/Home/Homepage/TTV_Home.aspx#”, navOpenInBackgroundTab);

oIE.Navigate2(“https://internetleadcapture.dynamics.com/Home/Dashboard.aspx?dl1prm=%3fuflcid%3den-US%26DLExternalIdValue%3dhttp%3a%2f%2fimginc.crm.dynamics.com&wa=wsignin1.0″, navOpenInBackgroundTab);

oIE.Visible = true;

I thought this was pretty cool, anyway. The variable oIE points to an instance of IE, and you just make calls to the “Navigate2″ method, passing in the URLs you want to open on the tabs. Then set the Visible property to “true”.

So how do you run an application like that? I wanted shortcuts from my desktop, so I started off by creating a shortcut to run wscript.exe:

  1. Right-click your desktop, click New, then Shortcut.
  2. Enter “wscript.exe” in the Type the location of the item box, click Next, then Finish.
  3. Right-click the new shortcut (it should have the Windows Scripting icon attached to automatically) and click Properties. It should look like this:

Notice that in mine the “Start in” parameter is “windir” – this is the folder where Windows sits; conventionally that’s c:\Windows, so that’s where the Windows Scripting Host will look for parameters by default. So as long as I save my crmsites.js file into the c:\Windows folder, all I need to do is supply the file name in the Target field, like this:

So finally, after making copies of the js file, substituting in the right URLs and creating wscript.exe shortcuts pointing to each one, I can just double-click any of my shortcuts and open up a new IE window with each page on its own tab.

For example, I double-click “My fave blogs”:

 

And in a few seconds, the six blogs with which I start my Dynamics CRM day all show up in one window:

Comments (3)

URL-Addressable Forms and Internet Explorer Tab Sets

Combine these for an Efficient, CRM-Centric User Experience

Dynamics CRM has a trick referred to as “URL-addressable forms”, which is a fancy way of saying that certain forms can be navigated to directly and opened in their own Internet Explorer window, bypassing the underlying UI within which they are normally contained. This can be handy in lots of situations. Here are a couple:

  • Suppose you want to add value to or extend a separate application with related information contained within CRM. For example, think of a SharePoint library containing proposals or other documents pertaining to accounts. A column in the SharePoint document library could contain a clickable link that would pop open the Dynamics CRM form for the account.
  • Certain areas within Dynamics CRM are a little bit crowded when contained within the full UI. If you can navigate to one of these directly you can free up some screen real estate and create a more productive user experience.

The second one is the topic of this article, and it’s one I’ve written about before, in the context of the Dynamics CRM service calendar. It’s easy to see the advantages of direct navigation by comparing the following two screen-shots. The first one shows my company’s service calendar contained within the standard Dynamics CRM UI; the second shows it being accessed directly.

The two most important takeaways are the additional room you free up with the direct navigation approach, and the way you do it. You can navigate directly to your service calendar by taking the standard URL you use to navigate to your Dynamics CRM, dropping the “/loader.aspx” bit, and adding “/sm/home_apptbook.aspx”.

Don’t look for any intuition here, just do it. J

Why does this Matter and What’s it got to do with IE Tab Sets?

It matters because the more things that are exposed directly, the more you can take advantage of this direct navigation technique. (I’ll get to tab sets in a sec)

In Dynamics CRM Online, more things are exposed in this way than in the on-premise edition, especially after the November 2009 Service Update. Here are two of my favorites:

  • Navigate directly to your sweet brand-new home page dashboard by substituting “/Home/Homepage/TTV_Home.aspx” for “/loader.aspx”
  • Navigate directly to your Internet Marketing dashboard with the more cryptic “https://internetleadcapture.dynamics.com/Home/Dashboard.aspx?uflcid=en-US&DLExternalIdValue=http://<organization name>.crm.dynamics.com” (e.g., for me, it’s imginc in place of the <organization name>, and remember these last two are Online only features for now!)

Now you could navigate to all these pages separately, but it’s a lot more convenient if you bundle them all up in an Internet Explorer “Tab Set”, like the following screen-shot illustrates:

To summarize, there are two big advantages of this approach:

  1. Navigating directly to one of these areas (service calendar, Internet Marketing dashboard, home page dashboard…) gives me more room. This is more useful than ever with the charts we can expose on the home page dashboard post November 2009 Service Update.
  2. Bundling them together in a single IE tab set means I don’t have to remember URLs and I can open them all at once, every time I want to live my so-called Dynamics CRM life!

I put together a Captivate recording to show how to bundle several windows up into a single tab set. Let me know what you think!

Cheers,

Richard

Comments (3)

Creating Charts with the Dynamics CRM Online Chart Designer

November 2009 Service Update Article #3

In another article, I did a quick write-up and linked to a recorded tutorial on how to use the charts that come built-in to Dynamics CRM Online. Basically, they are available to end-users, who can use them to personalize their home page, with up to four charts across the new horizontal “Chart Pane”.

The only entities that arrive stocked with charts are:

  • Accounts
  • Activities
  • Campaigns
  • Cases
  • Events
  • Leads
  • Opportunities

     

For example, Account comes with three charts, providing graphical counts of your accounts across territories, territories and owners. The Case entity ships with fifteen (!), most of which show distributions of cases (using counts, again) across various attributes like origin, priority, type and so forth. Opportunities, on the other hand, are all about sales, and the ten charts built-in for that entity are almost all different cuts of forecasted (open) and historical (closed) sales.

 

I encourage you to explore these built-in charts and see what’s available, for a couple reasons:

  • The charts provide a good guide for what kind of information is commonly tracked in Dynamics CRM, and more importantly, what kind of information your organization should be tracking. For example, if your Accounts by Territory and Accounts by Industry charts show you a single big bar labeled “Blank”, you might consider defining and using meaningful values for those two attributes!
  • After you know what’s available, you’ll know what you need to create, which brings us to the topic of this article.

Creating Charts with the Chart Designer

You can add custom charts for either system entities or custom entities. Assuming you’ve got sufficient privileges (by default, contained only in the security roles “System Administrator” and “Customizer”), you add them using a new tool called the “Chart Designer”, which is available through the familiar entity customization UI:

  1. In the navigation area, click Settings, then click Customization.
  2. Click Customize Entities.
  3. Locate the entity to add a chart for, and double-click it to open it.
  4. Click Charts, then click New. The Chart Designer opens. Here’s a screen-shot of it on top of the slightly modified customization UI (for Contact, in this example)

 

The Chart Designer is a self-contained one-window application, which as you can see from the picture, requires you to specify the following properties to build your chart:

  • Record Type View. Select from existing system views in the drop-down list. Every chart is based on a view, and the view does the data filtering work. When you create a new chart you may need to create a new view first, although you might be able to use one of the existing views.
  • Chart Name is self-explanatory.
  • Legend (Series). I’ll refer to this as the “Series”, but whatever you call it, it’s what provides the data for your chart: the height of a bar in a bar chart, or the percentage of the pie a piece takes up. If you select a text field you can only select “COUNT” as the “aggregate”. If you select a numeric field you’ve got a bunch of options (MAX, MIN, SUM, etc.)
  • Horizontal (Category). The Category represents the values across which the data will be distributed. So for a bar chart, the height of the bars will display the aggregated data, and you’ll have one bar per category. Two examples:
    • If you want to see the number of accounts in each territory, make a chart based on the Active Accounts view, and select Account Name as the Series and Territory as the Category.
    • If you want to see the total of account annual revenue just for your accounts, distributed across industries, select My Active Accounts as the view, Annual Revenue (Base) as the Series, and Territory as the Category.

     

Here are a few tips, tricks and gotchas, based on my admittedly limited experience with the tool:

 

  • Views must be published before they can be selected (to base a chart on), and charts must be published before they can be selected (in the dashboard). Notice the Publish button in the customization UI.
  • Within the Chart Designer, the “preview” that’s displayed is real data and it displays in real time. You can use this as a kind of a what-if visualization tool, seeing how your data are distributed across different attributes for the Category value, for example.
  • It took me a while to figure out how the “Sales Funnel” chart type worked. I thought there was some behind the scenes magic dependent on having a staged workflow for opportunities, and that it only worked for opportunities, or something arcane like that. But if you want to figure out the “Sales Funnel”, try this:
  1. Open up the Opportunity entity’s customization UI, and click Charts.
  2. Double-click the out of the box Sales Pipeline chart. Depending on … you may see an inherently uninteresting funnel with one data point, as I did the first time I tried it:

     

  3. That’s because the out of the box version uses Pipeline Phase as the category attribute. If it doesn’t contain any data every category in the sales pipeline funnel goes into the “blank” category. So just change the category to something that contains data, and you can get a nice pipeline funnel. For example, my organization uses a different attribute to represent our sales pipeline: the system picklist, “Sales Stage” (attribute name “salesstagecode”). Here’s what the pipeline funnel looks like if all I do is change the Category to a field with data:

     

    Apparently what the sales funnel chart type does is to “display values as progressively decreasing proportions” (from the online help). You can see in the screenshot that in this case it works as expected. I’ve experimented with different attributes for the category and got different results, however, such as the aggregates for the category values not appearing in “progressively decreasing proportions”. There are definitely some nuances I don’t understand about this chart type yet, so if you’ve got it nailed, please let me know!

Summary, What’s Missing

After a custom chart is created and published, it will be available for use by any user (with sufficient privileges) on their homepage dashboard. I haven’t yet figured out a way to create a chart and then make it available to all users, so the (apparent) fact that each user must go through the steps required to personalize their home page dashboard in order to consume these charts…well, it seems like a bit of a limitation. These must be exposed somehow, but like I said, I haven’t figured that one out yet, so if you have, please let me know!

So at least as far as I’ve been able to tell so far, custom charts can be created by a user with sufficient security privileges and then consumed by users as a personal configuration only. It would be nice if you could create a shared dashboard page that exposed the same charts to multiple users, but like I said…I haven’t figured that one out yet.

In the meantime, here’s something that’s better than nothing: if you add “/Home/Homepage/TTV_Home.aspx” immediately after the “dynamics.com” part of the URL you use to get to Dynamics CRM Online, at least you can get a nice personal dashboard that displays bigger charts without the baggage of the rest of the UI. For example, if I navigate to https://imginc.crm.dynamics.com/Home/Homepage/TTV_Home.aspx, here’s what I see:

Cheers –

Richard Knudson – richardk@imginc.com
new web site: www.IMGinc.net

Comments (3)

Many to Many Relationships and Advanced Find

In another article I discussed the different kinds of entity relationships that can be created in Dynamics CRM 4, and in particular, how to create many to many (a.k.a. “N:N”) relationships. But once you’ve created an N:N relationship and entered some related information, how can you tell what’s related? Advanced Find works great for this, but as David Challener pointed out in a recent comment on my article, it’s not exposed very obviously within the AF UI.

Anyway, here’s a short video that shows how to create an N:N relationship, and how to create an Advanced Find query to see which records are related:

Leave a Comment

More Thoughts on XRM

I’ve written a few articles on the “XRM thing”, and why the Dynamics CRM 4.0 is such a great platform for the development of line-of-business applications. At a recent meeting of the Dynamics CRM User Group we had a very good presentation from Microsoft’s Bob Piskule. Along with Bob, Microsoftie John O’Donnell provides adult supervision when we DCRMUG’ers meet at their Downers Grove office for our monthly meetings. Bob and I had a brief exchange towards the end of the session (you can view the recording from this page) that crystallized my thinking on some XRM topics, which I’ll try to summarize here.

What if they took the “C” out of CRM?

I’ve had a few recent customer conversations where the “C” part of CRM got in the way of the conversation. They were interested in developing a custom application that I knew would be a great fit for Dynamics CRM, but it wasn’t going to use much if any of the baseline feature-set of the product (sales, marketing, customer service). If you aren’t familiar with the platform, I can imagine it’s a little hard to think about an application built in Dynamics CRM that has nothing to do with its core features! But that’s really what the XRM concept comes down to: you can use the platform to develop any application, whether it has anything to do with “customers” or not.

The exchange I had with John was an extension of these XRM lines of thought: what would a real XRM platform look like? It won’t be too long before companies who aren’t using any of the built-in functionality start wondering why they’re paying for it. I’d be surprised if Microsoft hasn’t been approached already on the topic.

Or what about a developer who builds an application on the XRM platform and wants to sell a jillion seats. At $44/seat (the retail price of the Pro version of Dynamics CRM Online, on a per-user per-month basis), $44 jillion might be cost prohibitive, but he might be willing to pay $25k for an unlimited seat license in return for not being able to use any of the sales, marketing or service core feature-set.

XRM you can do Now

There actually are some options along these lines available now. There’s a “connector” license you can purchase for a one-time fee. If you have the connector you can expose read/write forms to users without a per-seat license fee. The catch is that the forms have to be ones you create yourself with custom .NET code, and you don’t get any of the built-in user experience goodness like reports, Advanced Find and so forth.

This approach is better than nothing, but it excludes what in my view is the secret sauce of of the platform: the native customization techniques exposed entirely through the web UI in Dynamics CRM.

Create an XRM Application in 5 Minutes

I’ll present an example here that illustrates the bare essentials of what you can do now, using the current capabilities of the Dynamics CRM customization feature-set (this works identically in the CRM Online or on-premise versions). It is simple, but if you’re new to this it illustrates some important customization techniques. And even if you aren’t the person who will be implementing customizations for your organization, it shows how you can “take the C out of CRM”, which is essentially what the XRM discussion is all about. Here’s the executive summary:

  • Create a new security role. New security roles (created “from scratch” – that is, NOT by copying an existing security role) contain no privileges to any entities by default, so the only way to expose entities to a user with this security role is to explicitly add privileges. I called it “XRM User”, for the purposes of the demo.
  • After creating the XRM User security role, I added privileges to it that will expose only some of the custom entities my organization uses.
  • For a specific user, remove any existing security roles and assign the XRM User security role only.
  • For the custom entities I wanted this user to see, I customized them so that they only appear in the “Workplace” area in the site map.
  • I also customized our Site Map, changing the name of the “Workplace” are to “IMG Workspace”. This isn’t essential, but it does illustrate that you can make the site map appear however you want it to.

The main point of this exercise is that you can easily strip down Dynamics CRM so that users see only the entities you want them to see, mixing and matching entities from your Great American XRM application with anything from the core feature set.

Let me know what you think of my awesome XRM application, and if you want to do it yourself, follow these steps:

Create the XRM User Security Role with privileges to none of the built-in entities, and only to the “XRM” entities you want to expose:

  1. In the left navigation area, click Settings, then click Administration.
  2. Click the Security Roles link, then click New to create a new security role.
  3. Call it “XRM User”, use all of its default settings (remember: a security role created from scratch like this has permissions to almost nothing!) and save it.
  4. Click on the “Custom Entities” tab for the security role, and add the privileges you want for any custom “XRM” entities you want to expose to these users.
  5. Pick a user, and remove all of their current security roles, and assign them this new “XRM User” security role only. (If you want to prank you buddy, use his or her user account. If you’re in one of those buttoned down corporate environments where things like messing with people’s user accounts are taken seriously, use a dummy account or do this in a sandbox environment.)

Customize XRM Entities so they appear only in the “Workplace”

For each entity, follow these steps:

  1. In the left navigation area, click Settings, then click Customization.
  2. Click the Customize Entities link, then select the entity you want to customize.
  3. Double-click it to open its customization form, then uncheck everything in the “Areas that display this entity” section except for the Workplace.
  4. Save and close the form, then publish.

Customize the Site Map

  1. In the left navigation area, click Settings, then click Customization.
  2. Click the Export Customizations link.
  3. Select Client Extensions from the View drop-down, and select Site Map from the list.
  4. Click Export Selected Customizations, and OK to confirm.
  5. Save the file to disk somewhere you won’t forget about it.
  6. Extract the zip file and edit the extracted XML file with Visual Studio, or XML Editor, or Notepad or whatever text editor you like.
  7. Find the line that looks like this:

<Area
Id=Workplace
ResourceId=Area_Workplace
ShowGroups=true
Icon=/_imgs/workplace_24×24.gif
DescriptionResourceId=Workplace_Description>

 

  1. At the very end of the line, add a “Title” attribute with whatever custom title you want for your XRM Workplace:

<Area
Id=Workplace
ResourceId=Area_Workplace
ShowGroups=true
Icon=/_imgs/workplace_24×24.gif
DescriptionResourceId=Workplace_Description
Title=IMG Workspace>

 

  1. Save the file, and go back into XRM – er, Dynamics CRM.
  2. In the left navigation area, click Settings, then click Customization.
  3. Click the Import Customizations link. Browse to the saved XML file, and import it.
  4. When you refresh the browser, you will see the Workplace customized with the new name you’ve given it.

After you complete these steps, you can get a good visualization of how customizable the platform is by signing in first as a System Administrator or somebody with lots of privileges. Here’s what it looks like for me, for example, in my “normal” CRM Online production organization:

Then, sign in as the user you assigned the “XRM User” security role to. Make sure that’s the ONLY security role they have, otherwise it spoils everything! Here’s what it looks like to that user:

 

This user doesn’t have privileges to see any entities except for the five custom ones exposed on the “IMG Workspace” site map area, so none of the traditional CRM areas – Sales, Marketing, Service – appear. She can click Advanced Find but can’t see anything except the specific entities her security role grants her privileges to.

Wrapup

Like anything else, it takes some time to learn how to build custom XRM applications on the Dynamics CRM platform. But once you’re up to speed, there’s no question that it’s a more productive approach to application development than most of the alternatives. My guess is, it would take about 10-20% of the time to create an XRM application on Dynamics CRM that it would to create it using C# and SQL Server. To be clear, I’m saying it’s reasonable to expect, for a comparable application, 5-10x more productivity on Dynamics CRM than with traditional development approaches.

The flip side, of course, is the licensing model. With the DIY C#/SQL approach I don’t have any user CALs to purchase. So the platform decision amounts to trading off developer productivity against licensing costs. I’ll close out by characterizing three scenarios I think are pretty common and provide some guidance on the decision process for each:

  • Organizations who have already licensed Dynamics CRM have an easy choice: don’t do any more development of line of business apps in Access or C#/SQL or whatever other alternatives you might consider. Most or all of your application development should be done in CRM.
  • Organizations considering the purchase of a CRM should incorporate the potential XRM benefits of Dynamics CRM into their decision process. It might not be obvious that when you’re comparing different CRMs for your sales/service/marketing functions, you should incorporate developer productivity on entirely different XRM apps into the decision process. But I think sometimes this could be an important factor.
  • Organizations or individuals developing standalone XRM apps with potentially large user populations, many of whom might be outside the firewall. For this scenario the current licensing model for Dynamics CRM will make it prohibitively expensive for many. Let’s hope that changes!             

 

Comments (6)

XRM Unleashed

At the September DCRMUG meeting (www.DynamicsCRMUserGroup.com) Microsoft’s Bob Piskule gave an excellent presentation and demo on the topic of Microsoft’s XRM platform.

For me, one of the most interesting things about the session was Bob’s presentation of the more-or-less official Microsoft positioning statement on XRM. Up until now most of the discussions I’d seen were by “outsiders” such as myself. (For example, here’s an article I wrote).

Here’s a summary of how Microsoft describes XRM:

Microsoft Dynamics XRM is an application platform layer that sits on top of CRM, designed to accelerate the development of relational business applications through flexible dynamic application services.  XRM’s multi-tenancy allows you to build and run as many line of business applications as you need on a single platform.  XRM also leverages other Microsoft technologies as building blocks including:  Office, Outlook, SQL Server, .NET and Windows. 

XRM can be used for vendor, asset, property, employee, program, recruit, grant, contractor, fleet, resource, product, licensing, contract, lifecycle management and more.  The possibilities are endless.  
Here’s Bob’s demo:

Comments (1)

Email Record Links from a Dynamics CRM Workflow

It’s easy enough to email another CRM user a link to a record. If you open up a form for almost any record type in Dynamics CRM, you can pull down the Actions menu and select the Send Shortcut command to do this. Dynamics CRM will open up your mail client, and insert a rather complicated looking link which the recipient will be able to click to navigate directly to the record (assuming they have read permissions!)

For example, here’s what it looks like from an opportunity record:

Here’s what it looks like for an account record:

While your specific links will be different than mine (mine are for records contained in my CRM Online database, and the nasty-looking 25-character GUID uniquely identifies CRM records so it better be different!), the general structure will always be the same. I’ll come back to that point a little later, since it will solve a problem for us.

Problem: a Workflow-generated email cannot send a record link

So…while you can use the menu command I just mentioned to manually email a link to a record, you cannot email a link to a record from within a workflow. This might sound somewhat obscure, but it actually comes up a lot, and when you run into it, it just seems like something you should be able to do! Fortunately, there’s a relatively easy fix you can implement, with just a pinch of customization and a smidgeon of script. I’ll show you the solution next, but first, let me illustrate the problem in a little more detail.

Suppose I want a workflow to automatically send an email alert any time something important changes about an opportunity record. Here are a few scenarios to illustrate:

  • If the pipeline stage of an opportunity record changes, send an email alerting the sales manager.
  • If the current date is with three days of an open opportunity’s estimated close date, send a reminder email to the opportunity owner.
  • If an opportunity is closed as “Lost”, send an email alert to the owner’s manager.

You can come up with as many scenarios as there are organizations in the world, but in all of them, it would be nice to include a simple clickable link in the body of the email, so the recipient of the alert can navigate directly to the record in question.

As you know if you’ve read my book on Dynamics CRM workflows, there are many things you can do with Dynamics CRM workflows…but unfortunately, this is not one of them! I’ll illustrate with a simple alert email, sent by a workflow that runs automatically any time specified values of the opportunity entity change.

The following screen shot shows the Set Properties form for the workflow’s Send e-mail action. For demo purposes, the email simply goes to me, and I’ve used Dynamic Values to populate the body of the email with presumably interesting information about the current opportunity.

There is an eponymously titled field you can insert for any entity in Dynamics CRM, in this case, using the “{field name{entity name}}” characteristic of the workflow design environment, it’s the {Opportunity{Opportunity}} you can see in the figure. The problem with that is that it’s only a clickable link to the record if it’s on the Regarding field…and the Regarding field only appears if you happen to be viewing the email activity within Dynamics CRM.

Here’s what an email sent by this workflow looks like in Dynamics CRM (e.g., as a History item associated with the opportunity record):

But if, like most people as you prefer consuming your email in Outlook or a non-CRM email client, you never see that Regarding field. For example, Outlook:

Solution: A Pinch of Customization and a Smidgeon of Script (and URL Addressable Forms)

If you’ve read this far, I’m grateful, and you may have noticed the “Link to record” field that’s appeared in a couple of screen shots. That’s the solution, and it uses a technique called URL Addressable Forms, which simply means that every form in Dynamics CRM can be accessed via a unique URL, consisting of an entity-specific prefix combined with a suffix unique to a specific record. You can use the Send Shortcut command I started out by discussing to see what the prefix is for some common record types:

Common Record Types

Record Type Edit Form Prefix
Account https://imginc.crm.dynamics.com/sfa/accts/edit.aspx
Contact https://imginc.crm.dynamics.com/sfa/conts/edit.aspx
Opportunity https://imginc.crm.dynamics.com/sfa/opps/edit.aspx
Case https://imginc.crm.dynamics.com/cs/cases/edit.aspx
Marketing Campaigns https://imginc.crm.dynamics.com/ma/camps/edit.aspx

 

You can use a custom attribute for any entity you want to include a clickable link for by following these steps:

  1. Customize the entity in question (e.g., Opportunity) by adding a new attribute. I added a custom attribute to the Opportunity entity, called it “Record Link” (it has a corresponding schema name), and gave it the following properties:

     

    The most important is to make it a Type of “nvarchar”, since that’s the only type that has the clickable link format of “URL”. Make sure it’s long enough. I made mine 200, but you can always come back and increase the maximum length (unlike the type and format values, which can’t be changed once the custom attribute is created.)

 

  1. Once the attribute is created, the question is how to put the value into it. This really is just a smidgeon of script code – one line of Jscript you can put in the Opportunity form’s OnSave event:

     

    crmForm.all.img_recordlink.DataValue = ‘https://imginc.crm.dynamics.com/sfa/opps/edit.aspx?id=’+crmForm.ObjectId;

That’s pretty much it. If you implement this you’ll notice that since I wrote this code for the form’s save event, the new “Record Link” field won’t contain anything until a record’s form has been saved at least once after you’ve saved and published theses customizations. Too bad there’s not a built-in Record Link attribute for every Dynamics CRM entity. I guess I should add that to my top X list of new features that should be included in Dynamic CRM 5!

I wrote a book on Dynamics CRM workflows, by the way, and it contains tons of examples like this one and other useful workflows. You can purchase the book on Lulu.com or on Amazon, and if you do, you can also get a (free) subscription to the online version of the book, where you can download the workflows themselves, customizations, and related content.

Here’s a link you can visit to find out more about my book and purchase it:

Comments (12)

Synchronize Child and Parent Records – with Code

I posted an earlier article on this topic, based on a question I got from long-time Trick Bag reader Sherry Hale. She wanted to know if you can use an automatic workflow to push changes to an account record down to all of the child contact records. I said,

  1. Unfortunately, you can’t
  2. But you can do it with an On Demand workflow on contacts, if you don’t mind manually selecting all of the contact records and clicking the Run Workflow button
  3. You can also do it with code. I hadn’t done it before but I’d seen articles about it, knew it was out there somewhere, and asked if anybody had any good examples please send them along.

A few hours after posting the article, I received an email from Jim Steger. Jim is a principle with Sonoma Partners and co-author of two of my three favorite books on Dynamics CRM, Working with Dynamics CRM 4.0, and Programming Dynamics CRM 4.0. He reminded me of an example he’d included in his Working with book, and graciously consented to my posting the note along with the code. (I say “reminded” because his was the example I knew was out there somewhere and I’d just got done scouring the Programming book looking for it.)

So with that, below is the note and the code to push changes made to a parent record down to child records, using Accounts and Contacts as an example.

Jim: thank you so much!

Sherry: if you have questions about the code, ask Jim! J

 

*******

Hi Richard-

I wrote an example in my Working with Dynamics CRM 4.0 book that does something very similar in code to the request in your recent blog post. I did have to use a plug-in though and I used a custom attribute on the contact that would determine whether it should be sync’d with the parent.

You can download the code from Microsoft here:

http://www.microsoft.com/mspress/companion/9780735623781/

 

Regards-

Jim

 

 

It is not the simplest of code and might be optimized, but you should get the idea.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Web.Services.Protocols;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;
 
 
namespace WorkingWithDynamicsCrm4.Plugin
{
  public class AddressSync : IPlugin
  {
    /// <summary>
    /// This sample synchronizes a contacts address with its parent account asynchronously.
    /// </summary>
    public void Execute(IPluginExecutionContext context)
    {
      // Verify we have an entity to work with
      if (context.InputParameters.Properties.Contains("Target") && context.InputParameters.Properties["Target"] is DynamicEntity)
      {
        ICrmService service = context.CreateCrmService(false);
 
        // Obtain the target business entity from the input parmameters.
        DynamicEntity entity = (DynamicEntity)context.InputParameters.Properties["Target"];
 
        // Verify that the entity represents an account.
        if (entity.Name == EntityName.account.ToString())
        {
          Dictionary<string, Property> changedValues = new Dictionary<string, Property>();
          changedValues = SetChangedAddressValues(entity);
 
          // if we have a changed address value, then continue with the update
          if (changedValues.Count > 0)
          {
            Guid accountId = ((Key)entity.Properties["accountid"]).Value;
 
            // retrieve applicable contact ids
            BusinessEntityCollection contactsToUpdate = RetrieveContactsForAddressSync(service, accountId);
 
            // update all contacts found
            UpdateContactAddress(service, contactsToUpdate, changedValues);
          }
        }
      }
    }
 
    /// <summary>
    /// Stores address values.
    /// </summary>
    /// <param name="entity">DynamicEntity object.</param>
    /// <returns></returns>
    private Dictionary<string, Property> SetChangedAddressValues(DynamicEntity entity)
    {
      Dictionary<string, Property> changedValues = new Dictionary<string, Property>();
 
      AddStringPropertyToDictionary(entity, "address1_name", changedValues);
      AddStringPropertyToDictionary(entity, "address1_line1", changedValues);
      AddStringPropertyToDictionary(entity, "address1_line2", changedValues);
      AddStringPropertyToDictionary(entity, "address1_line3", changedValues);
      AddStringPropertyToDictionary(entity, "address1_city", changedValues);
      AddStringPropertyToDictionary(entity, "address1_address1_stateorprovincename", changedValues);
      AddStringPropertyToDictionary(entity, "address1_postalcode", changedValues);
      AddStringPropertyToDictionary(entity, "address1_country", changedValues);
      AddStringPropertyToDictionary(entity, "address1_telephone1", changedValues);
      AddPicklistPropertyToDictionary(entity, "address1_addresstypecode", changedValues);
      AddPicklistPropertyToDictionary(entity, "address1_shippingmethodcode", changedValues);
      AddPicklistPropertyToDictionary(entity, "address1_freighttermscode", changedValues);
 
      return changedValues;
    }
 
    /// <summary>
    /// Updates the contact record's address information based on the new values from the account.
    /// </summary>
    /// <param name="service">CRM service object.</param>
    /// <param name="contactsToUpdate">Collection of contacts to update.</param>
    /// <param name="newAddressValues">Dictionary of address values</param>
    private void UpdateContactAddress(ICrmService service, BusinessEntityCollection contactsToUpdate, Dictionary<string,Property> newAddressValues)
    {
      // Loop through each contact in the collection
      foreach (DynamicEntity retrievedContacts in contactsToUpdate.BusinessEntities)
      {
        try
        {
          DynamicEntity oContact = new DynamicEntity();
          oContact.Name = EntityName.contact.ToString();
 
          KeyProperty contactId = new KeyProperty();
          contactId.Name = "contactid";
          contactId.Value = ((Key)retrievedContacts.Properties["contactid"]);
          oContact.Properties.Add(contactId);
 
          // Loop through address dictionary and add the address values as properties to the contact
          foreach (KeyValuePair<string, Property> prop in newAddressValues)
          {
            oContact.Properties.Add(prop.Value);
          }       
 
          // Update the contact
          TargetUpdateDynamic target = new TargetUpdateDynamic();
          target.Entity = oContact;
 
          UpdateRequest update = new UpdateRequest();
          update.Target = target;
          UpdateResponse response = (UpdateResponse)service.Execute(update);
        }
        catch (SoapException ex)
        {
          throw new Exception(ex.Detail.InnerXml.ToString());
        }
      }
    }
 
    /// <summary>
    /// Returns all contacts from the account valid for address synchronization.
    /// </summary>
    /// <param name="service">CRM service object.</param>
    /// <param name="accountId">The identifier of the account.</param>
    /// <returns></returns>
    private BusinessEntityCollection RetrieveContactsForAddressSync(ICrmService service, Guid accountId)
    {
      // Set up standard query expression
      ColumnSet cols = new ColumnSet();
      cols.AddColumns(new string[] { "contactid" });
 
      QueryByAttribute query = new QueryByAttribute();
      query.EntityName = "contact";
      query.Attributes = new String[] { "parentcustomerid", "sonoma_syncaddresswithparent" };
      query.Values = new Object[] { accountId, true };
      query.ColumnSet = cols;
 
      try
      {
        // Retrieve the values from CRM as a dynamic entity
        RetrieveMultipleRequest request = new RetrieveMultipleRequest();
        request.ReturnDynamicEntities = true;
        request.Query = query;
 
        RetrieveMultipleResponse matchingContacts = (RetrieveMultipleResponse)service.Execute(request);
        return matchingContacts.BusinessEntityCollection;
      }
      catch (SoapException ex)
      {
        throw new Exception(ex.Detail.InnerText);
      }
    }
 
    /// <summary>
    /// Helper method to add string properties to the dictionary
    /// </summary>
    /// <param name="entity">DynamicEntity to evaluate.</param>
    /// <param name="attribute">Attribute name.</param>
    /// <param name="newValue">Attribut value.</param>
    private void AddStringPropertyToDictionary(DynamicEntity entity, string attribute, Dictionary<string, Property> newValue)
    {
      if (entity.Properties.Contains(attribute))
      {
        StringProperty prop = new StringProperty();
        prop.Name = attribute;
        prop.Value = entity.Properties[attribute].ToString();
        newValue[attribute] = prop;
      }
    }
 
    /// <summary>
    /// Helper method to add picklist properties to the dictionary
    /// </summary>
    /// <param name="entity">DynamicEntity to evaluate.</param>
    /// <param name="attribute">Attribute name.</param>
    /// <param name="newValue">Attribut value.</param>
    private void AddPicklistPropertyToDictionary(DynamicEntity entity, string attribute, Dictionary<string, Property> newValue)
    {
      if (entity.Properties.Contains(attribute))
      {
        Picklist picklist = new Picklist();
        picklist.name = attribute;
        picklist.Value = ((Picklist)entity.Properties[attribute]).Value;
 
        PicklistProperty prop = new PicklistProperty();
        prop.Name = attribute;
        prop.Value = picklist;
        newValue[attribute] = prop;
      }
    }
  }
}

Comments (5)