How to show SharePoint document list on main CRM form

When you enable the SharePoint integration for CRM, you get the ability to view a document list view by navigating to the document area on the form. Often, users want have this list of document available directly on the main form and not have to navigate to another page. Here is one way to do it, applicable for the “old fashion” SharePoint integration using the SharePoint List Component for CRM. It does not apply to server-based SharePoint integration with CRM. This is an unsupported customization, use at your own risk. 

What you need

  • SharePoint integration enabled and configured for the target entity (i.e. list component installed, existing SharePoint Site & folder)
  • an IFrame on the form
  • a way to get the full URL of SharePoint folder associated to your record (could be a field that you automatically populate on the entity with a plugin, could be retrieving the SharePoint Document Location records using JavaScript when for form loads, etc.)

How it works

When the document view is loaded, there is a URL pattern used by the system to display the list component with the documents:

http://sharepointdev/crm/crmgrid/crmgridpage.aspx?langId=en-US&locationUrl={document location url}&pageSize=250

What you can deduct from the URL above:

{SharePoint Root Site}/crmgrid/crmgridpage.aspx?langId={Language}&locationUrl={Document Location Url}&pageSize={Page Size}

Grabbing that Url with the correct parameters and pasting in browser will display the list of document for the target CRM record. In short, all you have to do is display that Url constructed properly inside an iFrame on your CRM form (see illustration below). Please note that this can have a performance impact on how quickly the form loads (this component can take longer to be loaded and displayed.

image

Code snippet

Javascript Method to load the content


var documentSiteUrl = ""; /* Find a way to get this information – can be read from a hidden field on the form. */
var parentSite = ""; /* Find a way to get this information – can be read from a hidden field on the form. */

if (documentSiteUrl == "" || parentSite == "") {
   return;
}

// Build document location URL - Set IFRAME target
var docViewUrl = parentSite;
if (!StrEndsWith(docViewUrl, "/")) {
   docViewUrl = docViewUrl + "/";
}

var userLanguage = "en-US";
if (Xrm.Page.context.getUserLcid() == "1036") {
   userLanguage = "fr-FR"
}

docViewUrl = docViewUrl + "crmgrid/crmgridpage.aspx?langId=" + userLanguage + "&locationUrl=" + documentSiteUrl + "&pageSize=250";

var documentIFrame = Xrm.Page.ui.controls.get("IFRAME_Documents");
if (documentIFrame != null) {
   Xrm.Page.ui.tabs.get("Documents").setVisible(true);
   documentIFrame.setSrc(docViewUrl);
}
else {
   Xrm.Page.ui.tabs.get("Documents").setVisible(false);
}

Dealing with record level access restriction with Dynamics CRM

CRM works extremely well with giving users access to records based on a different set of security configuration tools : cumulative security roles with a “most permissive win” mechanism, business units, team memberships, access teams, hierarchy and so on. One thing it does not do well is restricting access to specific record. Imagine the following scenario:

  • Company ABC uses Microsoft Dynamics CRM to manage its cases
  • An employee leaves company XYZ to join ABC
  • After joining ABC, the new employee is given access to Dynamics CRM and has access to ongoing and past cases, say in his/her region
  • Company ABC has open cases against firm XYZ. The employee should not be able to see those cases because it represents a conflict of interest (e.g. he/she might give insights to his/her old friends at XYZ)

The following image provides an illustration of what we are trying to accomplish.

image

If you have worked with Dynamics CRM and know its security model, you can already read between the lines here. There are no easy ways to make this happen. This article provides a possible solution for this requirement based on a recent experience on a large CRM implementation.

Ruling out Team Membership & Ownership

In our scenario, members of a team or a business unit get access to all records  owned by their team or business unit. If we follow basic team/BU record ownership, the problem in this case is that once a record needs to be isolated from one individual member of the team, one of two things needs to happen:

  1. The record owner has to be changed (it can no longer be the team everyone is a member of) and the record needs to be shared with users who can still see it, but not with the individual that is getting the restriction applied OR
  2. The individual who is getting a restriction applied has to be removed from the team and all the records owned by his/her team need to be shared with him/her except the one he/she is restricted to see.  This technique implies heavy maintenance since the user will need to access new cases created for the team he/she used to be a member of.

Sharing in both cases can be done via the record share functionality, access team or any other mechanism that suits the business need. It should also be automated if there is a large number of records to share. You also need to save the information about the user and its restriction on a separate entity to be able to backtrack and understand why the records/ownership and so on have been modified.

Why we didn’t like the “Sharing” functionality

Using the out of the box sharing of record can cause problems in the long run. The PrincipalObjectAccess (POA) table gets bigger and bigger, causes performance issues and has to be cleaned up on a regular basis. In addition to that, the more access is controlled by sharing, the more you run the risk of having performance issues because of the complexity overhead in system lookups when it needs to display a record or list of records to users.

A solution using “Access Teams”

We decided to go with a design centered around Access Teams. The “Case” entity gets an “Access Team Template.” When a user is created and added to his/her group (team or business unit), we start a process to insert the user in the Access Team of each case related to his/her business unit. In order to restrict access to a specific case for a user, we can simply remove the user from the case’s Access Team.  For tracking purposes, we created a “Security Exception” entity that is created and has a relationship with a case and a user and an additional attribute that indicate the type and reason for the “Restriction”. To apply the access restriction on a case for a user (i.e. remove user from access team), we create a Security Exception record. We link the target case and user, and specify the restriction type. After the Security Exception record is created, a plugin is fired to perform validation and to remove the user from the case’s access team.

One of the reasons with went with that model was that we didn’t want to have a base security model that gets “broken” every time there a single person with restricted access, by changing record ownership or removing user from the team he/she is supposed to be a member of. With access teams, the record ownership remains the same, and users also remain on their team at all times which makes everybody happy and maintenance easier. The downside is that when a user is created, we have to look for all the cases in his/her business unit and manually (with code) add the user to each access team. Same when a case is created, users member of the case’s business unit have to be added to the case’s access team manually (also with code). That is the comprise we had to make.

As far as performance goes, the end results remain to be seen in the long run. Our system will have between 2000 and 3000 users when we complete our rollout. It will deal with over 1 million cases across multiple teams. Preliminary performance tests results look promising. I will repost if we get into any issue as it relates to performance.

It’s been a while! This feels great Smile  – Happy CRM’ing !

CRM 2015 is out!

For those who have been waiting, Microsoft Dynamics CRM 2015 is now available!

You can download the installation package here. Also, if you create a new instance of Dynamics CRM Online, you’ll notice that it has been upgraded. For the existing CRM Online customers, the process will be similar to the previous major update: they will have the option to schedule a date for their upgrade.

A few links that points to the nice features of CRM 2015 below.

Happy CRM’ing!