Friday, May 29, 2009

Setting the Full name format

I'm not sure how many administrators are aware of this but in the Settings --> Administration --> System Settings area of CRM there is an option to set the "full-name format." The most common are typically "FirstName LastName" or "LastName, FirstName". You have many more options here available to you.

However, please note that when you change this setting it effects any records created after the change, it DOES NOT update all of the existing records in the system. I once made the change after a client had been using the system for nearly a year and they then had a mix of contacts whose names appeared in different formats. It's really weird to look through a list of contacts where some are formatted one way and others are formatted another way.

So, if you are going to make this change, make it before you start putting data into your CRM system. Otherwise, if you have to make the change and you already have data in the system then you could perform an UNSUPPORTED update through SQL to the fullname field. It's simple and typically it doesn't take long to run (it just depends on the number of records you have). But it works and that's the import thing.

But now you know.

David Fronk
Dynamic Methods Inc.

Friday, May 22, 2009

The CRM_CalendarType parameter is missing a value

I've seen a number of posts that reference this issue and typically most people suggest to do the following:

1. Log on to the Microsoft Dynamics CRM 4.0 Web client as an administrator.
2. Click Settings , click Administration , and then click Security Roles .
3. Double-click the security role that you use.
4. On the Business Management tab, set the Read privilege of the User Settings entity at least to the Business Unit level.
5. Click Save and Close.
6. try to run the report

I recently saw an issue where this didn't work. What had caused the error was the uninstall of the CRM SSRS Data Connector. This uninstall did something to the SSRS Data Source that all of the CRM reports were using. This was confirmed by changing the way the authentication was configured. If a user was hardcoded into the Data Connector then everything would work, but all reports were run as that user. If the Data Connect was set to Windows Credentials then the CRM_CalendarType error would appear (that parameter could vary). Then if "Credentials Supplied by the User running the report" was used, an unauthorized error would appear.

What was found was that NTML had been turned off both the CRM and SSRS web sites. But turning NTML back on everything began to work again.

David Fronk
Dynamic Methods Inc.

Friday, May 15, 2009

Share Reassigned Records with Original Owner

There is a rather obscure system setting that gets overlooked in a vast majority of CRM implementations, it relates to sharing records with the original owner.

In the Settings --> Administration --> System Settings window, right on the General Tab. There is a section marked as "Set whether reassigned records are shared with the original owner". You can then choose whether or not to share reassigned records with the original owner.

What this does is any time you reassign a record it will share the record with the previous owner. Not just the original creator, but every owner after. So, this could be a great way for people outside of the sales department to follow up on leads that they have passed onto the sales team. See how deals they provided the company have panned out. Or cases created by the sales team can be viewed again to see how the customer support team handled a situation that a sales rep reported.

On the other hand, this could be a potential security nightmare for some companies where users should only see their own records. So, any time a sales person switches territories, or customer service reps who should only be servicing specific customers could potentially see more than is intended.

The good news is that fixing this is as simple as changing this option in the System Settings from "Yes" to "No". This will not undo anything that is already shared, but it will stop the system from sharing anything more if you don't want it to.

Knowing how data can be viewed helps when there is a "security breach" and suddenly people can see more than they are supposed to see.

David Fronk
Dynamic Methods Inc.

Friday, May 08, 2009

Sharing Records Automatically

From the number of implementations that I've done I believe sharing to be greatly underutilized. Part of the reason is that it is rather clicky in order to set up someone with the rights to see a record. It's hidden in the "More Actions" menu and then you can share with a user or a team. Teams help to facilitate mass sharing but still, most users and typical CRM administrators don't even know that teams exist.

Most implementations just open things up at the business unit level, or even the global level (depending on the size of the company) and don't even worry about sharing. However, there are times when certain information can be sensitive and necessary to restrict access to. Typically these things can be activities, opportunities, cases, services billed, hours worked, etc.

For instance, suppose sales reps aren't allowed to see support cases but are allowed to see the accounts that they manage. Any good account manager would want to know what support issues their account has been having before engaging on a new business proposal, so obviously the sales rep should get to see the cases related to the account.

All that is required is a couple of plugins at two main points and upon creation of a case and reassignment of an account. Whenever a case is created, get the account manager of the account on the case and share the case with that user. If the account gets reassigned, remove the share from the old account manager and add rights to the new account manager. Now with simple logic you can make data more accessible to those who should see the data without them having to do anything more than their regular job.

One side note, be aware that the more items there are under a parent record the longer the reassignments of records will take. For instance, if I reassign an account with 50 cases that's going to take a lot longer to complete the reassignment than it would if there were 5 cases, or even none. Just keep that in mind as you develop your sharing solution.

Pretty simple, and the SDK has some great examples on how to do this. Look up "AccessRights Enumeration", "GrantAccess Message", and "RevokeAccess Message" in the SDK and you should have everything you need.

Here's a quick example on how to share and give all rights to a user:

SecurityPrincipal principal = new
SecurityPrincipal();
principal.Type = SecurityPrincipalType.User;
principal.PrincipalId = new
Guid("7B222F98-F48A-4AED-9D09-77A19CB6EE82");
PrincipalAccess access = new
PrincipalAccess();
access.Principal = principal;
access.AccessMask = AccessRights.ReadAccess;

TargetOwnedDynamic target = new
TargetOwnedDynamic();
target.EntityId = new
Guid("6A92D3AE-A9C9-4E44-9FA6-F3D5643753C1");
target.EntityName = "incident";

GrantAccessRequest readGrant = new
GrantAccessRequest();
readGrant.PrincipalAccess = access;
readGrant.Target = target;
GrantAccessResponse readGranted = (GrantAccessResponse)crmService.Execute(readGrant);

access.AccessMask = AccessRights.WriteAccess;
readGrant.PrincipalAccess = access;
GrantAccessResponse writeGranted = (GrantAccessResponse)crmService.Execute(readGrant);

access.AccessMask = AccessRights.AppendAccess;
readGrant.PrincipalAccess = access;
GrantAccessResponse appendGranted = (GrantAccessResponse)crmService.Execute(readGrant);

access.AccessMask = AccessRights.AppendToAccess;
readGrant.PrincipalAccess = access;
GrantAccessResponse appendToGranted = (GrantAccessResponse)crmService.Execute(readGrant);

access.AccessMask = AccessRights.AssignAccess;
readGrant.PrincipalAccess = access;
GrantAccessResponse assignGranted = (GrantAccessResponse)crmService.Execute(readGrant);

access.AccessMask = AccessRights.DeleteAccess;
readGrant.PrincipalAccess = access;
GrantAccessResponse deleteGranted = (GrantAccessResponse)crmService.Execute(readGrant);

And here is an example on how to revoke access:

SecurityPrincipal principal = new
SecurityPrincipal();
principal.Type = SecurityPrincipalType.User;
principal.PrincipalId = new
Guid("7B222F98-F48A-4AED-9D09-77A19CB6EE82");
PrincipalAccess access = new
PrincipalAccess();
access.Principal = principal;
access.AccessMask = AccessRights.ReadAccess;

TargetOwnedDynamic target = new
TargetOwnedDynamic();
target.EntityId = new
Guid("6A92D3AE-A9C9-4E44-9FA6-F3D5643753C1");
target.EntityName = "incident";
GrantAccessRequest readGrant = new
GrantAccessRequest();
readGrant.PrincipalAccess = access;
readGrant.Target = target;
GrantAccessResponse readGranted = (GrantAccessResponse)crmService.Execute(readGrant);

Happy sharing!

David Fronk
Dynamic Methods Inc.

Friday, May 01, 2009

Open new Modal Window from onLoad

There are times where administrators and/or executives/managers want to alert users opening a given record about something important on a given record. If people need to be warned that they shouldn't call the contact because they are marked as "Do Not Call" or an Account is marked as being "On Hold". Those can typically be done through alerts. But if logic is needed off of related objects, such as only allowing 3 items per Order, or if a number of Cases have been opened within a given period of time, that's not as easy to do with JScript.

That means that you would need to take your logic to a webpage on the load of the given entity. But since you are opening another web page (through the window.open method) users would be able to click around it and ignore it, making the work of the web page useless.

If you use the window.showModalDialog method then you can change all that. A Modal Dialog requires users to take action on the newly opened window before they can get to the record they are trying to open. The method is very similar to the window.open method, allowing you to control the size of the page, what bars show (status, menu, etc) on the web page. Here's the code:


if(crmForm.ObjectId != null)
{
var url = "/ISV/Test/OrderDetailCheck.aspx?id=" + crmForm.ObjectId;
//window.open(url);
window.showModalDialog(url, "Order Detail Check","dialogWidth:200px;dialogHeight:150px;center:yes;status:no");
}

Just put this in the OnLoad of your entity and you now have a custom page that you can fully customize, modify and design that users must look at take action on before they can access a record.

David Fronk
Dynamic Methods Inc.