Sonoma Partners Microsoft CRM and Salesforce Blog

Update Rollup 7 Released

Lucky number 7s: Microsoft released the much-anticipated Update Rollup 7 for Microsoft Dynamics CRM 4.0 (UR7) on Friday, the same day Windows 7 was released to the public.

UR7 focuses on the Microsoft Dynamics CRM Outlook client and there are significant improvements to performance, stability and installation in both the online and offline Outlook clients.  Here are some highlights:

  • Faster startup. The load process was streamlined so that the CRM client loads in the background – so you can access e-mail and other Outlook records while the CRM client loads.
  • Improved performance. There are a few big changes here:
    1. Unnecessary processes were removed for the online version of the Outlook client, resulting in faster performance.
    2. E-mail tagging runs as a background process, so users who have a large number of tracked e-mail messages should see faster performance in Outlook.
    3. Synchronization between Microsoft Dynamics CRM and Outlook runs as a background process to minimize the impact on performance.
  • Improved stability. Some code updates help Microsoft Dynamics CRM handle state changes more efficiently, so authentication, hibernation and other changes in each client won't require you to restart Outlook.
  • Delegate support. If an Outlook user is a delegate for another user, the delegate can now track e-mails and other Outlook records in the other user's inbox, so records are attached to the correct owner in Microsoft Dynamics CRM.
  • Improved SMS support, including silent, unattended installations of the Outlook client. Users no longer need to be logged into the workstation during the laptop client installation process.
  • Better error logging in the synchronization process.
  • Streamlined setup and configuration processes.

Download UR7 now – As always, try it in a test environment before going live in production if you can. Also, before installing UR7 in your environment, check the known issues published by Microsoft. Note that UR7 is inclusive of the previous Dynamics CRM 4.0 rollups released by Microsoft, so if you have not updated your system recently, all released fixes will be applied with UR7.

UR7

Upcoming XRM Seminars

I just received this invite for three Microsoft-hosted xRM seminars. I am not sure if these are intended for partners only, but I thought I would share with everyone! :)

What is the X factor of your business?

XRM is built upon Microsoft Dynamics CRM’s business application development platform – a platform that can be transformed to support relational business applications.  Whether you’re looking to manage real estate properties, recruit employees, or manage franchises, XRM is a platform to solve your basic business needs no matter what they are.

That’s the X Factor in XRM.

Sign up today for a three-session webcast series on XRM for Microsoft Dynamics CRM Online, hosted by Microsoft Technology Specialists.  The first session will provide an introduction to XRM.  In the second session we’ll cover building business applications in XRM, and in the third session we’ll demonstrate XRM in application.

From Microsoft CRM to XRM: Introduction
Wednesday, October 28
8:30 – 9:30 AM Pacific Time
Presenters: Kevin Williamson and Jon White

From Microsoft CRM to XRM: Building Business Applications
Thursday, November 5
8:30 – 9:30 AM Pacific Time
Presenters: Jon White and Laura Robinson

From Microsoft CRM to XRM: XRM Demonstration
Wednesday, November 11
8:30 – 9:30 AM Pacific Time
Presenters: Eric Boocock and Special Guest

We look forward to seeing you at the webcasts!

Follow Sonoma Partners on Twitter!

While Sonoma Partners was one of the first CRM companies to launch a blog several years ago, I admit we’ve been a little slow with some of the other social media tools. Well NO LONGER! We launched a corporate Twitter account a week or so ago, so feel free to start following us if you’re so inclined!

Follow Sonoma Partners on Twitter

Managing Report Resources for Microsoft CRM

Today we welcome our guest blogger and colleague, Rob Jasinski, who discusses using SQL Server 2008’s Resource Governor to manage available report resources for Microsoft Dynamics CRM.

We’ve all had it happen; someone runs a very resource intensive report during the day which slows down the performance of CRM for all the users. This now can happen more frequently with the addition of the Dynamics CRM 4.0 Report Wizard. What if there were a way to be able to manage the server to limit the amount of system resources that are allowed for generating reports? You’re in luck! Now, a new feature in SQL Server 2008, allows you to create Resource Pools to manage the maximum amount of resources (CPU utilization and memory utilization) to be used by given processes that you define.

In this example, we’re going to create a Resource Pool that limits any queries being issued from our Reporting Services server to a maximum of 20% CPU utilization and 40% memory utilization. Also, we’ll only enable this feature during business hours (so during the evening, reports can get full system resources).

1. Enable Resource Governor on SQL Server 2008.
In SSMS, expand the Management tab and right-click Resource Governor and select Enable. 

2. Create a Resource Classifier function.
This function is what does all the assigning of processes to Resource Pools. Below is an example function:

use master
go
create function dbo.ResourceClassifier()
returns sysname with schemabinding
begin
declare @retval varchar(32);
if suser_sname() = 'DEV\ANAKOTA$' and
datepart(hour, getdate()) >= 6 and
datepart(hour, getdate()) < 19
set @retval = 'reports'
else
set @retval = 'default';
return @retval;
end
go
alter resource governor with (classifier_function = dbo.ResourceClassifier) 
go
alter resource governor reconfigure 
go
This is just a regular SQL Server function and the return values must be one of Workload Groups you created earlier. In this example, we check for the user name of “DEV\ANAKOTA$” (the user that Reporting Services uses to logon to the SQL Server in our example). Next we check the current time, if it’s within business hours (6am – 6:69pm), then we allocate this query to the “reports” Resource Pool, thereby making sure it won’t overload the SQL Server. Any other query is then sent to the “default” Resource Pool.



NOTE: Be sure to change 'DEV\ANAKOTA$' in the above script to use the appropriate user name for the reporting services accessing SQL. To determine the user name to compare, I ran SQL Profiler, ran a report from CRM, and captured what user was issuing the query from Reporting Services. There are also other system functions you can use, see http://technet.microsoft.com/en-us/library/bb933865.aspx for more detailed information on writing a classifier function.

3. Create and configure Resource Pool.
Right-click on Resource Governor again and select New Resource Pool… 


In the Classifier function name dropdown list, ensure that selection is your newly created function [dbo].[ResourceClassifer].



Then, in the resulting Resource Governor Properties window, create a new resource with the name of “reports”. Then enter the maximum CPU% and Memory% (in my example I set the values to 20 and 40 respectively).

Select the newly created “reports” Resource Pool that was created above. In the Workload Group for this resource pool grid, enter “reports” for the name of the Workload Group. The final result should look similar to the screen below. Click OK when you’re done.


Keep in mind that by limiting the resources available to a report, you are going to slow down the execution of those reports. Be aware of any SLA’s or other business needs before implementing this solution. Users may have specific business needs at certain times of the day or week to generate reports as quickly as possible. If you need faster performance time on reporting without affecting the transactional database, consider moving the reporting database to a separate SQL Server.

Using the new Resource Governor in SQL Server 2008 can be a quick and easy way to ensure that report processing won’t capture the majority of resources on your transactional SQL Server database.

Problems Registering Plug-Ins after a Domain Controller Change

While deploying a code update to a customer last week, we ran into timeout and SQL errors when trying to register a couple plug-ins. We've worked with this client before and never had problems registering our plug-ins, but since our last project the client had changed their domain controller.

After running a trace of the registration process, our team tracked the issue to the domain controller change, based on the following errors:

Exception in FindResultInDC: The server is not operational.

CrmSoapExtension detected CrmException:
System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.

MessageProcessor fail to process message 'UnregisterSolution' for 'none'.

Exception: System.Data.SqlClient.SqlException: Timeout expired.  The timeout period elapsed prior to completion of the operation or the server is not responding.
   at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection)

The cause of these errors is related to properly demoting the old domain controller. The domain controller was taken offline, but there were still records in Active Directory and DNS that routed requests to the old controller.

Following are the steps that resolved the issue for our customer:

  1. Added a String value in the registry under HKLM\Software\Microsoft\MSCRM called PreferredDc.
  2. Entered the NetBios Name of the target domain controller.
  3. Restarted the CRM server.

The customer was able to register the plug-ins successfully after making this fix. Note the registry key was included as a manual update in an earlier rollup and should alleviate some potential Active Directory issues. For more information, see this knowledge base article.

Plugin-registered
 

Streamline the Creation of New Related Records with jQuery

Today we welcome our guest blogger and colleague, Jeff Klosinski, who discusses using jQuery to create new associated records in CRM.

Do you or your users frequently create new records by opening a parent record, clicking a related entity on the left nav, and then clicking “New X” from the resulting grid? Wouldn’t it be nice if the “New X” button from the related grid were always at the top of your form?

I will show you how to do just that. On the way, you’ll see how to dynamically load a script and get to use some jQuery, too. Those not interested in the how or why can just skip to the end where I summarize what to copy where. Let’s get started!

My plan is to add an ISV button to the form, but I’ll need to give it either a URL or some JavaScript to execute…which means I need to find out how the “New Expense” button from the related grid works natively. Using the IE Developer Toolbar, I see that clicking the button executes some JavaScript:

locAddRelatedToNonForm(10007,10003,'{2D26CDCB-FB19-DE11-8B45-001EC935CFE9}', '')

I can see from the URL that the guid that the JavaScript is using is the id of the project record I currently have open, so if I give my ISV button that code exactly as I see it, clicking it would always create new Expense records related to “Initech – CRM Implementation”, the Project record I’m currently viewing. This is close to what I’m after, but definitely not right. Instead, I need to dynamically specify the id of the Project record that is currently open. Luckily, all CRM forms have a crmForm.ObjectId property that refers to the guid of the current record, which is what we’ll use in place of '{2D26CDCB-FB19-DE11-8B45-001EC935CFE9}' when I specify the JavaScript for my button. I can further see from the URL that the Project entity's type code (ETC) is 10003, so that tells me that the second parameter calls for the ETC of the current record. Another CRM form property available to me is crmForm.ObjectTypeCode, which can be used to return the correct type code at runtime. So, the XML I will add to my ISV.Config file looks like this:

<Entity name="new_project">
    <ToolBar ValidForCreate="0">
        <Button JavaScript="locAddRelatedToNonForm(10007,crmForm.ObjectTypeCode,crmForm.ObjectId,'')">
            <Titles>
                <Title LCID="1033" Text="New Expense" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Expense record" />
            </ToolTips>
        </Button>
        <ToolBarSpacer />
    </ToolBar>
</Entity>

The next image shows my button on the CRM form:

Great, just what I ordered. Well, almost. Two minor problems exist with this approach. The first is that this approach isn’t portable. It’s possible—and not uncommon—for ETCs of custom entities to be different between development, testing, and production environments. If I were to deploy this button to a client or other environment whose ETCs weren’t exactly the same as mine, my button would create new records of the incorrect type at best, and errors at worst. The second limitation is cosmetic: the button doesn't have an icon associated with it.

If neither of these two limitations concerns you, simply replace the first ETC (10007) with the one relevant to your entity, and use the code above. If they do concern you or, more likely, if you find my writing as difficult to put down as I do, then read on to see how we can use jQuery to solve both problems, resulting in an iconic button that is portable between entities and environments.

Since maintaining JavaScript that lives in the ISV.Config is a hassle, I’ll put the code that would have gone there into the onLoad event of my entity, and make the button’s ISV.Config JavaScript call one of the onLoad functions instead. In order for this to work, though, I will have to make sure to declare the button’s target function as a property of the window object so that is truly global and thus accessible by the button.

Since I’m planning on using jQuery within my code, I’ll first need to load it onto the form somehow. In this example, I dynamically load it from Google’s servers. I’ll also declare entity_OnLoad, the function which will eventually setup my icon, and newRelatedRecord, the global function which will be called by the button. newRelatedRecord will take one parameter, leftNavLabel, which the button will pass in. Here is what the code looks like:

var arr = new Array(),
    jQueryUrl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js',
    obj = document.createElement("<script src='" + jQueryUrl + "' type='text/javascript'>");
    
arr = document.getElementsByTagName("head");
// insert the script element before the end of the head element
arr[0].insertAdjacentElement("beforeEnd", obj);
// attach an event to be able to determine when the script is done loading
obj.attachEvent("onreadystatechange", Script_OnLoad);

function Script_OnLoad()
{
var rs = event.srcElement.readyState;
// check to see if the script is done loading
if (rs == "loaded" || rs == "complete") {
Entity_OnLoad(); // jQuery is done loading and we can continue
}
}

function Entity_OnLoad()
{
// nothing yet
}

window.newRelatedRecord = function (leftNavLabel)
{
// nothing yet
}


Note: Loading the jQuery library directly from Google’s servers may not be permitted in some environments. Alternatively, you could copy the library locally to your CRM Web server or even paste the code from the library directly to the top of your form’s onLoad event.

Next, I will fill out newRelatedRecord to find the ETC of the associated entity and create the button. To do this, I find the left nav link that pertains to leftNavLabel and extract the ETC from the src attribute of its corresponding img element. I will write a helper function called getIconImgByLeftNavLabel that harnesses the power of jQuery to do this pretty easily.

window.newRelatedRecord = function (leftNavLabel)
{
    var img = GetIconImgByLeftNavLabel(leftNavLabel),
        relatedTypeCode = img.src.match(/objectTypeCode=(\d+)&/)[1];
    
    // Call the function that will open up the new related record.
    locAddRelatedToNonForm(relatedTypeCode, crmForm.ObjectTypeCode, crmForm.ObjectId,'');
}

function GetIconImgByLeftNavLabel(leftNavLabel)
{
    var jQuerySelector = '#crmNavBar ' + 
        'a[title="View ' + leftNavLabel + '"] ' + 
        'img';
    
    var $img = $(jQuerySelector);  // The name I gave this variable starts with a '$'
                                   // to help remind me that it is the img wrapped in
                                   // a jQuery object, not the img element itself.
                                   
    return $img[0];     // Extract and return the actual img from the jQuery object        
}

The regular expression in img.src.match(/objectTypeCode=(\d+)&/)[1] searches the image’s src attribute for a pattern of the form objectTypeCode=X& where X is a number containing at least one digit that is immediately followed by an ampersand (&). The [1] immediately following the match() call gives me the part of the src attributes that corresponds to my first (and only) subexpression: (\d+).

Now let’s take a closer look at getIconImgByLeftNavLabel. Note that the explanation that follows is intended to help provide a basic understanding of how jQuery selector strings work and may not necessarily represent the exact steps jQuery actually follows when processing selector strings.

The first part of jQuerySelector, '#crmNavBar ', tells jQuery to first find the left nav bar (whose id is crmNavBar). jQuery selectors were designed to emulate CSS selectors, so using ‘#’ to denote the id of an element might seem familiar. The space at the end of this part indicates that the rest of the selector refers to elements that are descendants of crmNavBar. The second part of the selector string that I am building up, 'a[title="View ' + leftNavLabel + '"] ', tells jQuery to narrow the descendants of crmNavBar down to hyperlinks whose title attribute is exactly “View Expenses”. As before, the space after the right square bracket character tells jQuery that I’m actually interested in a descendant of the link element jQuery has selected for me. Finally, I tell jQuery to give me the img element that is a descendant of the link it just found for me by specifying 'img'. Not too bad when you break it down, right?

After updating my onLoad code to fill out newRelatedRecord, I’ll also add 3 buttons to the ISV.Config file:

<Entity name="new_project">
    <ToolBar ValidForCreate="0">
        <Button JavaScript="newRelatedRecord('Expenses')" >
            <Titles>
                <Title LCID="1033" Text="New Expense" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Expense record" />
            </ToolTips>
        </Button>
        <Button JavaScript="newRelatedRecord('Product Families')" >
            <Titles>
                <Title LCID="1033" Text="New Product Family" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Product Family record" />
            </ToolTips>
        </Button>
        <Button JavaScript="newRelatedRecord('Time')" >
            <Titles>
                <Title LCID="1033" Text="New Time" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Time record" />
            </ToolTips>
        </Button>
        <ToolBarSpacer />
    </ToolBar>
</Entity>

After publishing the entity and importing the updated ISV.Config file, my project form provides me with the following:

I could be done at this point, but without icons these buttons are sorely lacking. I’ll add some code to entity_OnLoad from the onLoad code that will look for my custom buttons, figure out which links they correspond to, and then copy their respective images to the buttons to give them a nice facelift:

function Entity_OnLoad()
{
    if (crmForm.FormType !== 2)  return;  
    
    var lis = $('li[action^="newRelatedRecord"]'),
        spans = lis.find('span.ms-crm-MenuItem-TextFirst'),
        
        labels = $.map(lis, function (li) {
            return li.action.match( /newRelatedRecord\((\'|\")([^\'\"]+)/ )[2];
        });
    
    $.each(labels, function (i, label) {
        // find img element using the helper and rewrap as jQuery object
        // so that we can use jQuery's clone and insertBefore functions 
        $(GetIconImgByLeftNavLabel(label)).clone().insertBefore(spans[i]);
    });
}

In the code above, I first check to make sure the form is an update form because it wouldn’t make sense to add a related record to a record that doesn’t exist yet (if we were on a Create form) and, natively, CRM doesn’t allow you to add related records to deactivated records (if we were on a Disabled form). Next, I find the elements that I will need. The variable lis is a jQuery collection of li elements whose action attributes start with "newRelatedRecord". Next, for each of the li elements found, I have jQuery give me a collection of descendant spans that have a class attribute of ms-crm-MenuItem-TextFirst and store it into the variable spans. Now I need an array whose cells correspond to each of the elements in lis, the values of which should be the labels I configured as parameters to the newRelatedRecord function when I specified the JavaScript for my buttons in the ISV.Config (i.e. Product Families from newRelatedRecord('Product Families')). I can easily construct this array with jQuery’s map utility function, which allows me to easily apply some processing to each cell in an array, mapping the results to a new, congruent array. In this case, I iterate over each element in lis and return the result of a regular expression that extracts the label in which I am interested. Then, I iterate over each of the cells in my labels array, using each label to grab (using the previously defined helper function) and clone its corresponding image, which I then insert directly in front of each of the corresponding spans I defined previously. Whew! As you can see, we can accomplishing a great deal with very few lines of jQuery code.

This means we’re finally done!

The final code for this sample is below. Add buttons to the entity that will be getting the buttons at the top of its form to the ISV.Config, updating the entity name and the parameter for the newRelatedRecord function with your appropriate values.

<Entity name="new_project">
    <ToolBar ValidForCreate="0">
        <Button JavaScript="newRelatedRecord('Expenses')" >
            <Titles>
                <Title LCID="1033" Text="New Expense" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Expense record" />
            </ToolTips>
        </Button>
        <Button JavaScript="newRelatedRecord('Product Families')" >
            <Titles>
                <Title LCID="1033" Text="New Product Family" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Product Family record" />
            </ToolTips>
        </Button>
        <Button JavaScript="newRelatedRecord('Time')" >
            <Titles>
                <Title LCID="1033" Text="New Time" />
            </Titles>
            <ToolTips>
                <ToolTip LCID="1033" Text="Create a new Time record" />
            </ToolTips>
        </Button>
        <ToolBarSpacer />
    </ToolBar>
</Entity>

Next, paste the following code where you specify onLoad code for the entity to which you added the buttons.

var arr = new Array(),
    jQueryUrl = 'http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js',
    obj = document.createElement("<script src='" + jQueryUrl + "' type='text/javascript'>");
    
arr = document.getElementsByTagName("head");
arr[0].insertAdjacentElement("beforeEnd", obj);
obj.attachEvent("onreadystatechange", script_OnLoad);

function script_OnLoad()
{
var rs = event.srcElement.readyState;
if (rs == "loaded" || rs == "complete") {
entity_OnLoad(); // jQuery is done loading and we can continue
}
}

function entity_OnLoad()
{
if (crmForm.FormType !== 2) return; // return if not an update form

var lis = $('li[action^=newRelatedRecord]'),
spans = lis.find('span.ms-crm-MenuItem-TextFirst'),
labels = $.map(lis, function (li) {
return li.action.match( /newRelatedRecord\((\'|\")([^\'\"]+)/ )[2];
});

$.each(labels, function (i, label) {
$(getIconImgByLeftNavLabel(label)).clone().insertBefore(spans[i]);
});
}

window.newRelatedRecord = function (leftNavLabel)
{
var img = getIconImgByLeftNavLabel(leftNavLabel),
relatedTypeCode = img.src.match(/objectTypeCode=(\d+)&/)[1];

locAddRelatedToNonForm(relatedTypeCode, crmForm.ObjectTypeCode, crmForm.ObjectId,'');
}

function getIconImgByLeftNavLabel(leftNavLabel)
{
var jQuerySelector = '#crmNavBar a[title="View ' + leftNavLabel + '"] img';
var $img = $(jQuerySelector);

return $img[0];
}


Publish the entity and import the ISV.Config file, and you have a versatile, user-friendly way to create new related records from any entity’s toolbar. This example barely scratches the surface of jQuery, so I hope you will consider it for your own CRM scripting needs. Good luck!

CRM Online update (known as R4) announced and coming in November

iStock_000009761161XSmall

We just received an email from Microsoft officially announcing an upcoming update to CRM Online:

“As part of Microsoft's commitment to ongoing innovation and customer success, we are set to deliver our next Microsoft Dynamics CRM Online service update in November 2009. This update will provide your organization with increased business benefits that accelerate time to value in areas such as:

  • Access to Microsoft Dynamics CRM Online through a range of mobile devices
  • In-page help and how-to guidance to provide an even richer experience for new users
  • The ability to add additional storage capacity to accommodate even larger customer databases
  • The introduction of a Home Page dashboard that gives improved visibility into data through embedded charts
  • A new release of Microsoft Dynamics CRM Online for Outlook with improved performance and usability
  • Enhanced data import capabilities through an updated import wizard experience

We will begin upgrading existing organizations in early November.”

Putting our own spin on this (and based on the previews we’ve seen), we are really excited for:

  • DASHBOARDS, DASHBOARDS, DASHBOARDS: Did I mention Dashboards?
  • Microsoft CRM Mobile Express: now available for CRM Online
  • New release of the Outlook client: This will be bigger than your typical bug fix/update rollup, think more along the lines of massive performance improvements.
  • Improved data import: The update message is a little vague above but we expect there will be significant improvements for customers migrating from competing CRM products (hint: SFDC).

Stay tuned for more details as Microsoft releases them to the public!

Topics: Microsoft Dynamics CRM Online

Microsoft Dynamics xRM – Professional Services (Part 1)

Abstract:  My next few blog posts will be focused on showing Microsoft Dynamics CRM as a “xRM” platform.  I plan to show real-world usages of Microsoft Dynamics CRM specifically as it applies to professional services organizations. 

Business Requirement: Tracking time

Proposed Solution: Microsoft Dynamics CRM

In most professional services organizations you need to track employee time as it relates to your customers.  This might mean tracking time against projects, cases, and/or customers.  Often times we find customers using timesheets that are either paper-based or tied to an accounting system that is severely lacking in functionality.   Tracking time is generally a cumbersome task yet a crucial component to generating revenue for a professional services organization. 

Utilizing the power of Microsoft Dynamics CRM we have developed an innovative approach to capture and manage time within a professional services organization.  The time application is developed using Microsoft Dynamics CRM (xRM) and is accessible both through the Outlook and Web clients.  Time entry can be accomplished in multiple fashions which makes it more likely that data is captured accurately, timely and with less resistance from the entire organization.

How it Works: The fundamental component is that we integrate time tracking to opportunities (projects) that our sales team closes using Microsoft Dynamics CRM.  Once an opportunity is closed a project record is created within Microsoft Dynamics CRM.  At this point, a project manager is assigned to the project and this person is responsible for building out the project team.  Members of the project team are then assigned to the project within Microsoft Dynamics CRM and they are able to begin billing against the project (I will get into more details of managing projects in a subsequent blog).  Simply tracking time to a project is not sufficient because you often times need to track time to specific items and sub-items (etc.).  The PM is able to transfer items from a functional specification document to the project in Microsoft Dynamics CRM making it available for the project team to track time to specific tasks. 

Time Summary Dashboard:

Time-Dashboard

In the Time Summary Dashboard you can enter time, view the week at a glance, view the total time for the month (billable vs. non-billable), and view past weeks of time.  In most cases, this is where an individual will go to see how they are performing based upon the expectations of the organization.  Note: The Time Summary Dashboard is available both within Microsoft Outlook and Internet Explorer.

Time Entry Options (Flexibility is the Key):

We recognize that individuals work in different fashions so we have created multiple ways for individuals to track their time.  The key is making it as convenient as possible to enter time.  Whether onsite working with a client, working from home, or working in the office everyone can easily enter their time into Microsoft Dynamics CRM.

Batch Time Entry: This tool allows you to enter your time in batches.  I use this one the most because I can enter my time on a daily basis in a very fast and efficient manner.  Think of this like a traditional paper time sheet where you are adding entries like line items.  You can constantly make changes to the entries up to the point where you decide to “submit” your time for the day/week/month (whatever your business requires).  The Projects, Items, and Project Tasks are all fed from Microsoft Dynamics CRM based upon the project information created for the specific customer.  Everything is tied out to security so that only the people who have access to that project see the related Items and Project Tasks.

BatchTimeEntry

Time Buddy: This application resides on your desktop and can be configured to launch during the initial login to your PC.  This is a great application for people who have to track time very closely to specific project tasks and clients.  You have the ability to start and stop time while tracking the time to a specific project, item, and task.  You can also manually update time by simply entering in your own hours and minutes. 

TimeBuddy

Old School CRM Time Entry: If you just had to do it you can always revert back to a core Microsoft Dynamics CRM form and enter in your time.

NativeCRMTimeEntry

Once everyone has submitted their time you can setup workflow rules for managers to approve time.  This is an optional feature but one that can add a lot of business value (like automatically sending email notifications to managers who are delinquent in approving time) .  Time approval is managed within Microsoft Dynamics CRM by simply marking time as “Approved.”  After all the time is approved you can then run Utilization Reports.  Since all of this data is being stored in the Microsoft Dynamics CRM database we can create reports with Microsoft SQL Server Reporting Services.  In addition, we can use the native Advance Find functionality of Microsoft Dynamics CRM to query the database on an ad-hoc basis.

Example Utilization Report:

Utilization

To complete the story of Time Entry we integrate all of this time data into our accounting package.  The best part about this integration is that it doesn’t matter what you are using for an accounting system.  We can very easily integrate to your accounting system and write these time records to your accounting database.  In our implementation, we create invoices based upon this integration and display all of the invoice information back within Microsoft Dynamics CRM for account management purposes. 

There you have it – Tracking time in Microsoft Dynamics CRM made easy.  This is a great example of how you can leverage the CRM application as a “xRM” platform. 

A few tips to keep you from going customization-crazy

I’ve been working with a customer recently on ideas for managing customizations. Like many organizations, this customer has several environments running Microsoft Dynamics CRM 4.0 and many people on staff making form and field changes with the customizations tools, which resulted in some errors when importing the customizations into another environment. There also were a few incidents in which one person’s changes were overwritten by another’s.

Using the handy documentation generator add-in for Microsoft Office Excel 2007, we created a change log that will be managed and updated by one administrator. The documentation generator allows you to load the customizations file from a Dynamics CRM environment, then parses it to compile form, picklist, and script configurations by entity in an Excel spreadsheet – a great tool for anyone who has had to document customizations!  It’s a free download from CodePlex if you’re interested.

I hope a future version of Dynamics CRM has auditing and a rollback feature in the customizations tools, but for now, we’ll make do with a well-defined process to manage the customizations. Here are a few other best practices to help manage customizations:

  1. Limit the number of people who make customization changes and if possible, divide ownership of entities so that more than one person isn’t likely to make changes on an entity at the same time.
  2. Select one environment (typically a development or test environment) as the master organization for all customizations, and make sure all changes are made and tested there before being exported and imported into another environment.
  3. When possible, limit the export to only the entities that were changed.
  4. The customizations are stored in the database, so all of the form layouts, client-side script and views are recoverable as long as you’re backing up your MSCRM database regularly.
  5. If an entity, attribute, or relationship is deleted, you must remove the object from each environment manually.

Excel-DocumentationGenerator