Tag Archives: CRM 2011

Dynamically Disable Ribbon Buttons in Dynamics CRM

Today I had to dynamically disable a custom Ribbon button.  My rule needed to be based on fields on the form and based on the form mode.  I only want the button enabled on the Update form and only when a certain checkbox is checked.

Here’s the steps.  These will work for CRM 2011 Ribbon buttons or CRM 2012 Command Bar buttons.

To modify the CRM Ribbon / Command Bar I use the excellent Ribbon Workbench tool from Develop 1.  To use this tool download their solution file, import it into CRM and then open the Solution.  The Ribbon Workbench UI will launch.  You will be prompted to open a solution.   For best performance it pays to create a temporary solution that contains just the entity you wish to customize and the JavaScript web resources you need to refer to (if applicable).

Here’s my custom Ribbon buttons as seen in Ribbon Workbench:

image

You add custom ribbon buttons by dragging a “Button” from the Toolbox in the bottom left corner of the screen up into the ribbon.   Then you set the Button properties through the Property window on the right and define the Button’s Command through the Solution Elements tab in the bottom middle of the screen.

Back to our dynamic rule.  First step is to define an Enable Rule.  This is done from the Solution Elements tab.  Right-click on Enable Rules and select Add New:

image

Click the arrow to expand Expand Rules, you will see a new Rule listed:

image

Right-click on the Rule and select Add Rule:

image

Up will pop a bunch of Rule types for you to pick from.  You can chose options here if you want your Button to be enabled only for certain form modes, or in say the Outlook Client but not the Web Client.   In my case I want to control the state of my button based on the results of a JavaScript function so I’m going to choose “Custom Javascript Rule”:

image

Next, click on the CustomRule and then complete the Properties on the right.  The important properties here are the Java Script Web Resource library (which will need to be contained in the Solution file you selected when Ribbon Workbench launched) and the FunctionName:

image

So, obviously, those properties need to match to an actual JavaScript function you have loaded into CRM via a Web Resource.  Here’s mine:

image

The JavaScript function can execute any logic you like, it just needs to return true or false.  A value of true will result in the Enabling of the button, false will Disable it.

One last bit, we need to add the Enable Rule to the Command tied to the Button.   This is also done from the Solution Elements tab.  I already had a Command defined so I just right-click on it and select Edit Enable Rules:

image

Up pops a Rule selector, simply select your rule and push it over to the right via the Add > button:

image

If you didn’t have a Command defined for your Button you would need to right-click on Commands in the Solution Elements tab and select Add New and then add the Enable Rule.  And you would need to select the Command you created back in the Button’s properties.

Last step is to Publish the changes:

image

And that’s it.  The approach for dynamically changing the display state of a button is almost identical so you are not an expert in that too.

Happy ribboning.

Oh and yes this is all the same in CRM 2013:

image

Advertisements

Cannot Delete Plug-ins in CRM 2011

I recently had the less than enjoyable experience of hitting a new issue during a late night Production deployment.   This was perhaps the 6th deployment to this environment but the first time I had seen this problem.   The problem surfaced as an error during the deletion of the SDK Message Processing Steps of an existing Plug-in solution.  I typically delete all existing Steps and then delete the Plug-in Assembly before importing the new Solution zip file to ensure no retired Steps remain in the destination environment.   The CRM UI gave little information, just “an error has occurred”.  The CRM trace gave more details, but these didn’t immediately suggest the root cause:

“Error while normalizing non-case sensitive AD credentials for use on a case sensitive SQL installation”

“Unable to obtain DNS hostname of Active Directory domain controller with ntdsa object name”

“Action failed for assembly ‘XXXX.WMCRM.Plugins, Version=1.0.0.0, Culture=neutral, PublicKeyToken=4f1f52667a84f9b5’: Assembly must be registered in isolation., ErrorCode: –2147220906”

“MessageProcessor fail to process message ‘Delete’ for ‘sdkmessageprocessingstep’.”

I started to wonder whether my deployment user account had been demoted from being a Deployment Administrator so I tried to launch the CRM Deployment Manager application.  It failed to launch.  It repeated the error from the trace:

“Unable to obtain DNS hostname of Active Directory domain controller with ntdsa object name”

My googling efforts landing me on this post:  http://social.microsoft.com/Forums/en-US/crmdeployment/thread/a8abdbc7-fa4c-4f3d-8d9e-809e4a9dc3b8/  which didn’t match my scenario but one of the solution steps resonated with the error message I was seeing:

Add the Preferred Domain Controller  value to MS CRM registry entries: HKLM\Software\Microsoft\MSCRM

Step 1. Right Click and click on NewString value as "PreferredDc"

Step 2. Add the value to PreferredDc is YourDomainControllerName you can find this in your AD by typing the command in your cmd prompt echo %logonserver%

And those steps worked for me.  I ran echo %logonserver% to determine the Domain Controller my server was connected to and added a registry key to tell CRM that was my Preferred Domain Controller.  Immediately (no reboot required) Deployment Manager was working again and I was able to delete my SDK Message Processing Steps.

So it seems like the CRM Deployment Service caches a Domain Controller and the one cached was no longer working correctly.  I was able to ping it, so it was up, but it wasn’t able to perform the function requested of it. 

We removed the registry key when finished.  I don’t think we want to tie the CRM deployment service to a particular DC.  I am hoping to learn more about this from Microsoft to determine steps to avoid these steps in the future.   Caching a Domain Controller in an Enterprise setting where Domain Controllers come and go seems like a product deficiency.   Neither an IISReset or a server reboot helped us.

Hope this helps someone out there.

Duplicate Record Button using Jscript in Microsoft CRM 2011

As detailed here, Rollup Pack 8 for Microsoft CRM 2011 gave us a couple of shiny new jscript toys:

Xrm.Utility.openEntityForm(name,id,parameters)

and

Xrm.Utility.openWebResource(webResourceName,webResourceData,width, height)

In this post I will show you how to add a “Duplicate Record” button to a CRM form, using the new openEntityForm function.

First, lets add the button.  Download Erik Pool’s ribbon editor from CodePlex.  If you are still editing ribbon xml manually and not using this tool then you are mad.   Run the tool, connect to your CRM organisation and open the ribbon you wish to edit.  I am going to add my button to the Case form, adding to the last Group of buttons on the right hand side.  I click in that Button Group and then click New Button and name my button:

image

My button appears small by default so I change the Template Alias to Large.  I need an icon for my button and the one I see on the “Copy Selected” button looks good so I can click on that button and copy and paste the image properties from that button over to my new button:

image

I tidy the Label and Tooltip and then click on the Action tab and enter the name of my jscript library and function, which we will create next:

image

Finally, I save the change and then check my button appears in CRM:

image

I want to demonstrate copying a range of data types so I add a few custom fields to my Case form:

image

Ok, now we can write the jscript function.  There are 3 steps to this:

1. Collect field values from the source record

2. Define the values you want to populate into the destination record

3. Pop the form, passing across the values to be populated

I’ve pasted just the first part below.  Most of this is just me using CRM’s getValue() functon, but you will see I do some null value checks on the lookup fields (to avoid errors) and I also need to extract multiple values from each lookup field.  You will also note for the date field I call another function so that the value returned by the getValue() call gets converted into the MM/DD/YYYY format that the next step requires:

function DuplicateCase() {
    //get values from the Form
    var CaseId = Xrm.Page.data.entity.getId();
    var CaseTitle = Xrm.Page.data.entity.attributes.get("title").getValue();
    if (Xrm.Page.data.entity.attributes.get("customerid").getValue() != null) {
        var CustomerId = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].id;
        var CustomerName = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].name;
        var CustomerType = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].entityType;
    }
    if (Xrm.Page.data.entity.attributes.get("subjectid").getValue() != null) {
        var SubjectId = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].id;
        var SubjectName = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].name;
    }
    var CaseOriginCode = Xrm.Page.data.entity.attributes.get("caseorigincode").getValue();
    var CaseTypeCode = Xrm.Page.data.entity.attributes.get("casetypecode").getValue();
    var CaseDate = FormatDate("new_dateofincident");  // wants "MM/DD/YYYY" (this might be environment specific though)
    var CaseUrgent = Xrm.Page.data.entity.attributes.get("new_urgent").getValue();
    var CaseClaimAmount = Xrm.Page.data.entity.attributes.get("new_claimamount").getValue();
    if (Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue() != null) {
        var CurrencyId = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].id;
        var CurrencyName = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].name;
    }
    if (Xrm.Page.data.entity.attributes.get("ownerid").getValue() != null) {
        var OwnerId = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].id;
        var OwnerName = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].name;
        var OwnerType = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].entityType;
    }
    var CaseDescription = Xrm.Page.data.entity.attributes.get("description").getValue();

Here’s the second section of the function, here I am basically placing each of the values I extracted during step 1 into a parameter object (testing for and excluding null values as I go):

 

    //define default values for new Incident record
    var parameters = {};
    if (CaseTitle != null) {
        parameters["title"] = CaseTitle + " - COPY";
    }
    if (CustomerId != null && CustomerName != null) {
        parameters["customerid"] = CustomerId;
        parameters["customeridname"] = CustomerName;
        parameters["customeridtype"] = CustomerType;
    }
    if (SubjectId != null && SubjectName != null) {
        parameters["subjectid"] = SubjectId;
        parameters["subjectidname"] = SubjectName;
    }
    if (CaseOriginCode != null) {
        parameters["caseorigincode"] = CaseOriginCode;
    }
    if (CaseTypeCode != null) {
        parameters["casetypecode"] = CaseTypeCode;
    }
    if (CaseDate != null) {
        parameters["new_dateofincident"] = CaseDate;
    }
    if (CaseUrgent != null) {
        parameters["new_urgent"] = CaseUrgent;
    }
    if (CaseClaimAmount != null) {
        parameters["new_claimamount"] = CaseClaimAmount;
    }
    if (CurrencyId != null && CurrencyName != null) {
        parameters["transactioncurrencyid"] = CurrencyId;
        parameters["transactioncurrencyidname"] = CurrencyName;
    }
    if (OwnerId != null && OwnerName != null) {
        parameters["ownerid"] = OwnerId;
        parameters["owneridname"] = OwnerName;
        parameters["owneridtype"] = OwnerType;
    }
    if (CaseDescription != null) {
        parameters["description"] = CaseDescription;
    }
    if (CaseId != null && CaseTitle != null) {
        parameters["new_parentcase"] = CaseId;
        parameters["new_parentcasename"] = CaseTitle;
    }

And the last bit is simply:

    //pop incident form with default values
    Xrm.Utility.openEntityForm("incident", null, parameters);
}

Here’s how it looks in action.  Here’s my source record:

image

And here’s what pops up when I click the button:

image

To use this yourself in your unique scenarios you will obviously need to edit the getValue() and parameters lines to match your fields.  I’ve covered off the main data types and added a little bit of robustness to help guide you on this.   The openEntityForm utility certainly helps out here.

Here’s the jscript function in full and the missing FormatDate function:

function DuplicateCase() {
    //get values from the Form
    var CaseId = Xrm.Page.data.entity.getId();
    var CaseTitle = Xrm.Page.data.entity.attributes.get("title").getValue();
    if (Xrm.Page.data.entity.attributes.get("customerid").getValue() != null) {
        var CustomerId = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].id;
        var CustomerName = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].name;
        var CustomerType = Xrm.Page.data.entity.attributes.get("customerid").getValue()[0].entityType;
    }
    if (Xrm.Page.data.entity.attributes.get("subjectid").getValue() != null) {
        var SubjectId = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].id;
        var SubjectName = Xrm.Page.data.entity.attributes.get("subjectid").getValue()[0].name;
    }
    var CaseOriginCode = Xrm.Page.data.entity.attributes.get("caseorigincode").getValue();
    var CaseTypeCode = Xrm.Page.data.entity.attributes.get("casetypecode").getValue();
    var CaseDate = FormatDate("new_dateofincident");  // wants "MM/DD/YYYY" (this might be environment specific though)
    var CaseUrgent = Xrm.Page.data.entity.attributes.get("new_urgent").getValue();
    var CaseClaimAmount = Xrm.Page.data.entity.attributes.get("new_claimamount").getValue();
    if (Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue() != null) {
        var CurrencyId = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].id;
        var CurrencyName = Xrm.Page.data.entity.attributes.get("transactioncurrencyid").getValue()[0].name;
    }
    if (Xrm.Page.data.entity.attributes.get("ownerid").getValue() != null) {
        var OwnerId = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].id;
        var OwnerName = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].name;
        var OwnerType = Xrm.Page.data.entity.attributes.get("ownerid").getValue()[0].entityType;
    }
    var CaseDescription = Xrm.Page.data.entity.attributes.get("description").getValue();

    //define default values for new Incident record
    var parameters = {};
    if (CaseTitle != null) {
        parameters["title"] = CaseTitle + " - COPY";
    }
    if (CustomerId != null && CustomerName != null) {
        parameters["customerid"] = CustomerId;
        parameters["customeridname"] = CustomerName;
        parameters["customeridtype"] = CustomerType;
    }
    if (SubjectId != null && SubjectName != null) {
        parameters["subjectid"] = SubjectId;
        parameters["subjectidname"] = SubjectName;
    }
    if (CaseOriginCode != null) {
        parameters["caseorigincode"] = CaseOriginCode;
    }
    if (CaseTypeCode != null) {
        parameters["casetypecode"] = CaseTypeCode;
    }
    if (CaseDate != null) {
        parameters["new_dateofincident"] = CaseDate;
    }
    if (CaseUrgent != null) {
        parameters["new_urgent"] = CaseUrgent;
    }
    if (CaseClaimAmount != null) {
        parameters["new_claimamount"] = CaseClaimAmount;
    }
    if (CurrencyId != null && CurrencyName != null) {
        parameters["transactioncurrencyid"] = CurrencyId;
        parameters["transactioncurrencyidname"] = CurrencyName;
    }
    if (OwnerId != null && OwnerName != null) {
        parameters["ownerid"] = OwnerId;
        parameters["owneridname"] = OwnerName;
        parameters["owneridtype"] = OwnerType;
    }
    if (CaseDescription != null) {
        parameters["description"] = CaseDescription;
    }
    if (CaseId != null && CaseTitle != null) {
        parameters["new_parentcase"] = CaseId;
        parameters["new_parentcasename"] = CaseTitle;
    }

    //pop incident form with default values
    Xrm.Utility.openEntityForm("incident", null, parameters);
}

// This function takes the fieldname of a date field as input and returns the value of that field in MM/DD/YYYY format
// Note: the day, month and year variables are numbers
function FormatDate(fieldname) {
    var d = Xrm.Page.data.entity.attributes.get(fieldname).getValue();  
    if (d != null) {
        var curr_date = d.getDate();
        var curr_month = d.getMonth();
        curr_month++;  // getMonth() considers Jan month 0, need to add 1
        var curr_year = d.getFullYear();
        return curr_month + "/" + curr_date + "/" + curr_year;
    }
    else return null;
}

Global Search Add-ons for Microsoft CRM 2011

In this post I provide a quick run down on the Global Search add-ons available for Microsoft CRM 2011.   Here are the candidates:

    I will cover the Installation experience, Setup options and the end user search experience…

 

Global Search by Akvelon

Installation

Global Search is provided as an executable that you install.  Once quirk of the installation process is the license activation screen launches in the context of your default Organisation and you cannot select an alternative Organisation.  Checking the instructions, you need to manually navigate to a different URL to activate the product for a different Organisation.  This is a bit lame, most other ISV vendors do a better of job of this.  Akvelon’s installation instructions are of a high standard though.

Oh and uglier still, I notice the URL refers to the ISV folder on the CRM Server – eek!  That is not supposed to be used anymore with CRM 2011, these guys haven’t updated their installer or architecture for CRM 2011 to the current standard.  The product will work, but this architectural decision leaves me with some doubt about this vendor.  Hopefully, plans exist to update this.

image

There is a second installer you need to run if you wish to allow searching of Attachments, it installs some supporting technologies for you.  Looks like Attachment search is enabled through a crawler executable that indexes the contents of attachment files every 15 minutes.

 
Setup

Before anyone can use Global Search they must be assigned a Global Search security role.  Three custom CRM Security Roles are provided:

image

The Administrator role grants access to global settings, the Experienced Users role grants users access to personal search settings and the the 3rd role grants access to just the Search tool.

To configure global settings you navigate to Akvelon’s configuration screen, which has been added to the CRM Settings menu:

image

Before attachment search will work you need to enable it via the Attachment Search configuration button.  A configuration screen will pop:

image

Similarly you can enable SharePoint search and Email indexing (enabling email indexing improves email search performance):

image  image

By this point you should get the picture, these guys have built out a fairly extensive search solution.  I wonder, do CRM users really need this much functionality?   I haven’t come across this before, Microsoft CRM mostly contains structured data.  However, once you start talking using CRM heavily for tracking emails and attachments decent search does become more important.  Out of the box, Microsoft CRM has always suffered from poor email search, it has limited CRM’s ability to act as a centralised email repository.  The unspoken reality is even if you are tracking emails religiously into CRM you really need to store your emails locally as well for this reason.  Interesting.

Anyway, from the settings screen I can enable additional entities for search (including custom entities):

image

And I can configure search fields and the view definition of the search results:

image

 
User Experience

The user manual suggests End users assigned  the minimal permission security role should see a search screen like the below:

image

This doesn’t seem to be the case for me, I see the search screen with the personal search settings visible as I should if I had the ‘Experienced Users’ role.  Perhaps this is because I have the OOTB Systems Administrator role – not sure.   This pic from the user manual matches what I see:

image

Putting personal search settings to the side, this is the search user experience users get…

If you search for “Happy” the search engine will check the CRM entities enabled for search to see if the fields enabled for search contain the text “Happy”.  The results are summarised per entity:

image

You can expand the search results to see individual records (which you can then double-click to open):

image

The column headings are sortable and if the search results for any particular entity exceeds 5 records then filtering becomes enabled and anything you type in under the column headings instantly filters the results. This makes for a nice user experience:

image

If an entity has been enabled to show related entities in the search results you will be able to drill through to related entities like you can see with the Opportunity Notes below:

image

You can use a wildcard to search for e.g. “Hap&y”.  You can type in 2 words such as “Happy Gilmour” and any record that contains both “Happy” and “Gilmour” in its search fields will be returned, even if those words are in separate fields.

When searching you can tick the Attachments option to have the search extended to include CRM attachments:

image

image

The personal search settings that can be configured are much the same as the global settings.  The user experience is the same:

image

 

Conclusions for Akvelon
  • Lots of functionality
  • Strong personalisation features
  • Seems robust
  • Fast searches (albeit on my small sample database)
  • Easy to use
  • User interface looks very CRM 4.0, but it gets away with it
  • Presentation of search results could look better, it looks a bit messy
  • Installation into ISV folder is not a good look, but then again, not sure it really matters
  • Because indexing is used, recently edited items may get missed by the search

 

PowerGlobalSearch by Power Objects

I’m going to describe the User Experience before Installation & Setup this time as the Setup explanation will make more sense this way (and installation is dead simple)…

User Experience

End users access PowerGlobalSearch from the CRM menu, with the application appearing in the main application pane just like a CRM view.   The look and feel is very Microsoft CRM 2011, they’ve done a great job with that.

Your search string is entered in the top right hand corner, which was counter intuitive for me, but obviously not a big stumbling block.  Search results are rendered in the main part of the screen and a preview pane appears on the right showing a preview form of the currently selected record:

image

First thing I noticed was the search is not doing a ‘contains’ it is doing a ‘begins with’.  So my search for “Happy” only brought up a subset of my records.  Switching to “*happy” returned more results:

image

Search results are listed without any grouping, you get one big list, one set of shared columns.

You can re-sort the search results by clicking on any column header and the Status dropdown allows you to easily expand your search to include inactive/completed records:

image

Above that Status dropdown you can click use the Filter dropdown to deselect entities, to filter the search results:

image

No other filtering is available, Akvelon offers more functionality here.

It is interesting that Power Objects have adopted this consolidated view approach where all records from the different entities are all displayed in the same column set.  It makes for a much cleaner UI but it means only a finite number of fields can be displayed in the search results.  Akvelon is more configurable here, but I do prefer Power Object’s cleaner lines.

One feature that Power Objects has over Akvelon is the shortcut buttons along the top of the search results, these allow you to quickly create new records in relation to a record in the search results:

image

(not sure how much this would be used in reality though)

Installation & Setup

Power Objects provide their add-on as a managed solution so installation only requires a quick import. After install you need to open the imported solution to access the configuration screen for license entry and setup:

image

On the Setup screen we can configure which CRM Entities should be searched against (supports custom entities too).  You define which fields should be searched against and you also define which 2 fields from that entity should appear in the Name and Detail columns of the search results:

image

e.g.:

image

Also configurable is the reading pane, this is configured through a drag and drop UI that seemed quite cool at first but then started to feel a little buggy to me (e.g.: once I defined the reading pane for my SMS entity the SMS search results stopped showing up):

image

Conclusions for Power Objects
  • Less functionality then Akvelon, but has a Reading pane and presents search results in a different way, which might appeal
  • Fast searches (albeit on my small sample database)
  • Easy to use
  • User interface looks very Microsoft CRM 2011, nice and modern, very clean
  • Simple installation and minimal footprint on your CRM server
  • Buggy configuration (for me at least)
  • Silverlight app, won’t run on 64-bit browsers or 64-bit version of Outlook Client (this is an issue for any Silverlight based ISV add-on) – and what is the future of Silverlight?
  • What’s up with Power Objects comic book style website?!?

 

PowerSearch by MSCRMAddons.com

Installation & Setup

PowerSearch is provided as an executable that you run to install their product.  Installation process is straightforward and at the end you will see 2 new managed solutions in your CRM system, a new configuration screen under CRM’s Settings menu and the Power Search utility added to your Workplace menu:

image

The Power Search configuration screen takes a while to load (the solution in general seems to be slower than the first two reviewed here).  The configuration screen presents entities configured for search in a list view:

image

You can add new entities (including custom entities) and remove unwanted entities.  The experience of adding a new entity is not particularly nice, with a small cramped screen and some less than intuitive fields for “Sort Order” and “Collaps on Rows” as you can see below:

image

You select which fields should be searched against, which columns should be displayed in the search results and which status fields should be considered as ‘Active’.

There is some sort of Favourites screen but the UI didn’t render large enough for me to be able to save any changes.  The presentation standard of this screen is not great.  In general, I wasn’t enjoying myself here, the experience was a definite step down after the first 2 products, but configuration is a one time thing so perhaps it doesn’t matter a whole lot.

User Experience

Searching is a slow experience and I found the the search results screen messy:

image

Conclusions for MSCRMAddons
  • User experience not as nice as competitors, didn’t perform as well during my (limited) testing

    Overall Conclusions

    Well you have 2 good products to pick here from Akvelon and Power Objects.  I think the critical decision factors will be price and functionality.

    I prefer the user experience with Power Objects clearly Akvelon packs in a lot more functionality – but do you need it?

    I priced both products recently for a 500 user deal and Akvelon’s purchase price was significantly higher then Power Objects’.  However, when I took into account annual costs over 3-5 years the gap closed significantly.  You will need to do your own price comparison for your user size to see which prices out better.

    Both products can easily be installed under a trial license.  Please use the Comments below to share your experiences and opinions.

    Metro UI coming to Microsoft Dynamics CRM

    Exciting first looks of future Microsoft CRM screens from Worldwide Partner Conference 2012 courtesy of MSDynamicsWorld.com:

    (you need to register for free at the above site to read their article) 

    Dynamics CRM Metro app Sales Home

    Microsoft are suggesting we might start to see some of these screens by March 2013 (in their 2012 Winter release).

    Dynamics CRM Metro App Team management

    One more screen:

    Dynamics CRM Metro app Opportunity

    Exciting stuff!

     

    Smile

    Service Contracts & Service Scheduling in Microsoft CRM 2011

    Another cheat sheet, this time covering Microsoft CRM’s rarely used features of Service Contracts and Service Scheduling…

    Service Contracts

    Contract Templates are defined under Settings \ Templates (where Mail Merge Templates are also maintained)

    On the Contract Template you indicate whether the Contract provides for a fixed number of Cases, a fixed number of Hours or covers a number of days.   And I guess that provides fairly good cover.  If I think of support contracts my employer offers they tend to fall into one of those 3 categories.

    You can also define the hours and days of the week that the Contract covers (that’s what the little green dots are about in the screenshot below) – but settings these limits seems to have no effect:

    image

    Contract Templates cannot be edited once created, if a change is required you need to create new Contract Templates.  You don’t seem to be able to delete or deactivate unwanted Contract Templates once they have been used at least once.

    When you go to create a Service Contracts CRM acts slightly differently from normal, it pops a dialog and asks you to select a Contract Template, you chose one and only then does the Service Contract form appear.  So, the Contract Template is not just a data entry shortcut, it drives the behaviour of Service Contracts.

    On the Service Contract you specify the Customer the Contract is for and you enter the start and end date of the contract.  This date range is validated against later when you try and charge Cases to the Contract:

    image

    The price of the Contract and the level of service provided for that price is defined one level down, on the Contract Line.  The only real important field on the Contract Line is the “Total Cases/Minutes” field.  This is what the Customer is buying from you – whether it be 20 Cases, or 3000 minutes (50 hours).  It is this amount that will be get deprecated when you charge Cases to the Contract in the future:

    image

    There’s a bunch of other fields on the Contract Line, you can specify a Product and enter pricing details.  And of course you can create multiple Contract lines under a Contract if you want. 

    To activate the Contract so that Cases can be charged to it you need to click the “Invoice Contract” button.  It doesn’t create an Invoice record, it just changes the status of the Contract to Invoiced.

    When creating a Case you can charge the Case to the Contract so long as the current date falls within the Contract’s Start and End dates and the Contract status is Invoiced:

    image

    Invoiced Contracts can be put on hold via the “Hold Contract” button, this temporarily prevents Cases from being charged to the Contract (I guess you might use this if payment lapsed).

    The “Allotments Remaining” balance on the Contract Line is deducted only when the Case is resolved.  There’s a field in the Case Resolution window where you can record the number of minutes to be charged to the Contract (for Contracts of that type):

    image

    I think that about covers it for Service Contracts.  If your requirements don’t fit within these parameters then I recommend a cautious review of the suitability of this out of the box design.  You may find adopting some custom entities and/or building out your own business logic extensions might be a better approach.  Like all CRM scenarios you need to measure the gap and look at the unique characteristics of the CRM entities and screens and decide whether those characteristics are of benefit or are in the way.

    UPDATE:  Just noticed that cancelled Contracts can be Renewed via a “Renew Contract” button.   This will create a duplicate Contract with a Status of Draft.   

    Here is more details on Contract Statuses, listed in the order of the Contract life cycle:

    Draft – after a contract is created, it is automatically assigned a Draft status. This indicates the contract is still under development. Draft contracts can be edited but they cannot be linked to a case.

    Invoiced – changing the contract status from Draft to Invoiced indicates your organization and the customer have agreed to the contract terms. A contract must have at least one contract line to be invoiced. A contract with a status value of Invoiced cannot be edited or deleted, it can only be cancelled or put on Hold.

    Active – once a contract is invoiced, it remains in an Invoiced state until the contract start date is reached. At that point, the contract’s status will be automatically updated to Active. You can link cases to a contract once the contract is in an Active state. A contract with a
    status value of Active cannot be edited or deleted, but new Contract Lines can be added (to allow extensions to the Contract).

    On Hold – an active contract can be placed on hold. A contract in an On Hold state cannot be edited, cancelled, or deleted, and it cannot be associated with cases. It can be reactivated by releasing the hold.

    Cancelled – an active contract can also be cancelled. When a contract has a status of Cancelled, it cannot be associated with cases. A cancelled contract can be renewed.

    Expired – a contract remains active until it reaches its end date, at which time its status is changed to Expired. Expired contracts can be renewed.

     

    Service Scheduling

    Setup steps for the Service Scheduling module need to be completed under Settings: Business Management. 

    Start by defining your Resource Groups.  Create a Resource Group for each types of Resource that you will need to schedule – e.g. if you are scheduling surgeries you might have the following Resource Groups: Doctors, Nurses, Surgeries and Anaesthetists:

    image

    Next identify each Resource under those Resource Groups.  Resources can be CRM Users, Teams, or Facilities/Equipment records.  Continuing with the Surgery example I would add My CRM Users that are Doctors to my Doctors Resource Group and then do the same for Nurses and Anaesthetists.  Finally, I would create new Facilities/Equipment records for each Surgery and add those to the Surgeries Resource Group:

    image

    Next define the geographic locations where your Resources can be utilised.  You create these as Sites.  Under each Site you select the Resources that are valid for that Site.   Later when scheduling you will take a customer request for a Service and the scheduling engine can optionally apply a Site constraint to ensure only Resources listed for the Site are scheduled. 

    image

    Next step is to define the Services that you will be selling to your Customers.   Stay in the Business Management area of CRM and go to Services, add a New record.  Give the Service a name, indicate the duration the Service should be scheduled for – e.g. 1 hour, 2 hours, etc. and set when the first appointment can be scheduled each day:

    image

     

    Next you need to define the resource requirements for the Service.  CRM has a unique UI for this bit, here’s an example where I say for the “Tummy Tuck” Service we need an Anaesthetist, a Doctor, a Surgery and 2 Nurses:

    image

    I’ve specified Resource Groups here but you can specify specific Resources instead if required – e.g. for the Tummy Tuck maybe you have to use Surgery A, or the Doctor has to be Ben Hanks.  

    You will see that Sites are mentioned as well, this is where you can limit the pool of resources by their Site associations (to prevent you scheduling resources from distant locations).

    Next, we need to define when our Resources are available.  Call up your first User and click on the Work Hours link.  A calendar will appear.  By default the Work Hours defined for Users equates to 24x7x365 availability – i.e. no constraint is imposed.  The same is true for Equipment/Facilities records.  This might be ok for Equipment/Facilities records but is unlikely to be ok for Users.  So, click on one of the days and then click the Delete button to remove the default work hours definition.  Click the Setup button and then select either the Weekly Schedule or Daily Schedule.    Then define the working hours for that resource:

    image

    There are options here to vary the working hours by day or have them the same each day.  You indicate which days of the week the User works and whether they should be considered unavailable on days where we have indicate the business is closed (e.g. on public holidays).  The Set Work hours link takes you to a sub-screen where you can define start and end times and any breaks:

    image

    You can also define any restrictions the Resource has in regards to performing certain Services at certain times.  e.g. perhaps our User here refuses to perform Tummy Tuck surgeries in the morning:

    image

    Last step is to define those business closures.  There’s a screen for that under Business Management, it’s pretty obvious how you create records there:

    image

    Ok, that’s everything setup.  CRM can now start assisting us with the scheduling of Services.  We will give CRM requests like “Mr Smith wants a Tummy Tuck in Auckland one morning next week” and CRM will use all of the setup configuration we have fed it to determine which applicable resources are available.  HOWEVER, CRM does not go as far as auto-scheduling.  You still need to pick from CRM’s search results the resource you want.

    image

    This scheduling is done from the Service Calendar.   On the Calendar you can chose to view a Day, Week or Month at a time, the view won’t typically fit on the screen, scrollbars allow you to scroll left to right to see the entire time period:

    image

    The “Type” dropdown above the calendar view allows you to choose the record type to display down the calendar.

    To schedule a Service you can click the Schedule button on the Ribbon and CRM will pop first a Service Activity form and then pop over top of that the Schedule Service Activity screen.   The Schedule Service Activity Screen is essentially an availability search screen that helps you assign Resources to the Service Activity record.

    Select the Customer, select the Service they are requesting, optionally select the Site where the Service is to be performed and then enter the customers scheduling preferences – e.g. they might want the Service scheduled for one afternoon next week:

    image

    You will notice that I’ve changed scenarios with my screenshot.   I got to this point with my Surgery example and hit the limitations of the Service Scheduling module (which I admit I had forgotten).  What I found was the grid at the bottom listed out all of available timeslots for all of the resources that met the requirements of my Service, however CRM doesn’t bundle these for you – it doesn’t say “hey next Thursday at 2pm you could go with Bob, Adan, Jill, Nina and Surgery A”.   It doesn’t even allow any useful sorting abilities to allow you to do this yourself.  And worse still, you cannot actually select more than one Resource on this screen.  The CRM scheduling screen just doesn’t support multiple-resource bookings.  So I changed my scenario to something a lot simpler. 

    My new scenario is Air Conditioning Servicing.  I offer a single Service: “A/C Service” and this Service requires 1 Technician for 1 hour.  Here I enable a prioritisation feature I didn’t mention earlier which will see the search results filtered based on who has the least number of appointments scheduled:

    image

    With this scenario the Schedule Service Activity screen works ok.  I scan the search results and click on line 3 to book Bob in for 1pm on the 8th July.  I click the Schedule button at the bottom of the form and the screen closes, passing that selection back to the Service Activity form that has been sitting in behind the search screen:

    image

    I enter a Subject and then Save & Close, I now see that hour of Bob’s time blocked out on the Service Calendar:

    image

    If later I need to reschedule this Appointment I can select the calendar item and then click the Reschedule button on the Ribbon.  This will pop the Service Activity record and the Schedule Service Activity screen over top of it and automatically execute a search against Bob’s availability to give me new slots to pick from:

    image

    To see all the jobs scheduled for a certain timeframe you can switch the Service Calendar from showing Resources to show Service Activities instead:

    image

    To tick these Service Activities off as they are Completed you can use the Change Status button on the Ribbon (these are Activity records so they shouldn’t remain open):

    image

    You can manually schedule/reschedule appointments in which case CRM becomes more of a validation engine then an availability search engine.  You will see alerts like the below which you can chose to ignore:

    image

    The Service Calendar supports Service  Activity and Appointment records.  I think Microsoft’s idea is that Appointments are periods of blocked time around which Service Activities can be scheduled – so they might be internal meetings / training or personal appointments.  When scheduling availability is validated against both of these calendar item types.  The Conflicts button on the Ribbon will highlight any scheduling conflicts with a red border:

    image

    I think that about covers it for Service Scheduling.  In summary, it doesn’t handle multi-resource bookings well.  It does an ok job with simple single-resource scheduling offering some good search abilities.  A couple things I haven’t mentioned is the Service Calendar needs to be manually refreshed when you change an existing calendar item, that’s not ideal.  A big concern to me as an implementer is neither the Service Calendar or the Schedule Service Activity screen can be customised.   This leaves me very uncomfortable, I normally have customisation options I can discuss with a customer – here the only answers are “Sorry, I can’t change anything” or “Sorry, we would have to build a custom version of this screen to give you that”.

    I think what you get with CRM’s Service Scheduling module is one of three things:

    1. It is a simple service scheduling tool that you can adopt and use as is (if you can fit your requirements into its functional breadth), or
    2. It is a sample application indicative of what you could build using CRM as a rapid development platform.  It can be used as a pilot or during design workshops to help you establish your requirements and design the solution that your business needs, or
    3. It is a validation engine for service scheduling.  You setup the rules and then schedule manually or via your own custom user interface and it will let you know when you break the availability rules.

    UPDATE 1:  I just spotted an almost useful tip in the Microsoft Coursewear on Service  Scheduling – you can access the Service Calendar directly via a URL like… 

    https://adventureworkscycle.crm.dynamics.com/sm/home_apptbook.aspx

    … which makes better use of the available screen real estate:

    image

    (but this is suitable only as a read-only view as without the ribbon appearing you cannot schedule new activities)

    UPDATE 2:  Something else I missed, Customers can have Service Preferences defined on their Customer record – e.g. Preferred User, Preferred Day:

    image

    These preferences appear in the form assistant and are considered by the search engine.  I suspect the “Least Busy” / “Most Busy” setting on the Service is given a higher priority by the scheduling engine then the customer preferences but the preferences are still part of its algorithm:

    image

    UPDATE 3: I forgot to mention Capacity.  You can define the Capacities of each Resource (Users and Facilities/Equipment records).  You enter this against their Work Hours (you have to click through to the work hours detail and then click the Show Capacity button):

    image

    This is where you can indicate that a particular Conference Room has a Capacity of 50 seats.  Then when you define your Services you can define what Capacity the Service requires – e.g. a “Room Rental (small)” might require a Capacity of 40:

    image

    Then when requesting available resources/times these requirements and constraints will be taken into account.

     

    I’m keen to hear where you have found CRM’s Service Scheduling module of use.  Please use the Comments feature below.

    Order Processing Features in Microsoft CRM 2011

    Need a cheat sheet on the out-of-the-box Products and Pricing features of Microsoft CRM?  How about the the Opportunity –> Quote –> Order –> Invoice process?  Ok, here you go…

     

    Defaulting of Currency and Price List

    • A default Currency can be specified under each user’s Personal Options and on each Customer record.   The Organisation too has a default currency set.  Default Price Lists can be specified on Customer records.
    • When creating a new Opportunity from the context of a Customer record the Currency and Price List specified on the Customer record will default down on to the Opportunity record.
    • When creating a new Opportunity outside of the context of a Customer record the Currency field defaults based on the value set in your Personal Options.  The Price List field does not default at all.  If you don’t have a Currency set under your Personal Options then the Organisation default currency applies.
    • Whenever selecting a Price List on an Opportunity, Quote or Order the list of selections will be filtered by the Currency specified.  i.e. each Price List is tied to a Currency.

    Product and Price Definitions

    • When defining a Products a Unit Group must be specified. 
    • The Unit Group is a collection of ‘units of measure’ that the Product can be priced in – e.g. you might have a Unit Group called “Cans” and within that Group you might have the following Units:  Each, 6-Pack, Tray, Carton and Pallet.  
    • The most granular unit should be defined as the Primary Unit – in the Can example this would be the “Each” Unit. 
    • On the other Units you define the unit translation required to get from the Primary Unit to this Unit, e.g. on 6-Pack you enter a quantity of 6 and on Tray you enter a quantity of 24.  Although I’m not sure this is used in anyway by CRM, CRM does not attempt to track inventory levels – that is really an ERP function.
    • Product Prices are stored on Price Lists.  Under a Price List you create an entry for a Product where you specify the Price for a particular Unit.  e.g.  I have a Price List Item on the “USD Retail” Price List for the “Coke Can” Product where I say $5 is the price of a “6-Pack”.
    • Each Price List item can have a specific Price entered against it or a % can be entered and the pricing derived by combining that % with the List Price or Cost Amount specified on the Product record.  This allows you to have standard costs and prices for the Product but varying Price Lists.
    • Discount Lists can be defined and applied to Price List Item records to add a Quantity Break discount table to the pricing (e.g. get 5% when you buy 10-20 units, get 10% off when you buy 21-30 units).

    Product Selection and Line Item Pricing

    • When creating a Opportunity, Quote or Order you need to specify a Price List before you can specify Products.
    • Then when you go to select a Product the Products displayed to you will be filtered to only those that have Prices on that Price List.
    • Having selected a Product you next need to select a Unit.  The Units you can select from are filtered to only those that appear on the Price List for the Product selected.
    • Lastly you enter a Quantity.  With those inputs specified CRM can now price your line item.

    User Entered Discounts

    The following discount types are supported out-of-the-box (other types require jscript/plugins):

    • A $ discount at the line item level, comes off of the line total (not the unit price)
    • A % discount at the header level, reduces the pre-tax, pre-freight total
    • A $ discount at the header level, reduces the pre-tax, pre-freight total, applies after the % discount

    Quotes

    • A Quote can be created from an Opportunity – most of the Quote details are automatically populated.
    • The Quote is automatically saved as it is created (you may see the screen flash as the form refreshes).
    • All of the product, quantity, discount and freight details can be changed if required.
    • When you are ready to present a Quote to a Customer you should click the Activate Quote button – this locks the Quote.  It can now only be changed via a Revision process which will maintain version history.
    • To change a Quote – e.g. to give the Customer a revised Quote – click the Revise button.  The Quote record will be duplicated and the original Quote flagged as Closed.  The new Quote will share the same Quote ID but have a unique Revision ID (behind the scenes it is a new Quote record with its own unique GUID).
    • Bill To and Ship To addresses can be keyed into the Quote or can be retrieved via the Lookup Address button.  Only child address records added against customers can be retrieved (this excludes the address1 and address2 address blocks on the customer record)  [correction:  address1 and address2 become selectable so long as the Address Name field is populated]
    • There is a “Get Products” button on the Quote form that will allow you to copy the Products from the Quote’s parent Opportunity down to the Quote record (presumably catering for scenarios where the Opp has been updated after the Quote has been created).  Fairly useless feature.
    • The “Print Quote” button launches CRM’s native Mail Merge feature.  You pick a Mail Merge template and Word will launch.  The user experience is dreadful.  The sample template included with Microsoft is abysmal.  You will need a better solution than this if you need to produce Quotes from CRM.  The minimal coding solution is to use an SSRS report but this is still a poor user experience, I would reach into the SDK for something a little smarter or go with a 3rd party add-on (e.g. MyCRM’s ePDF product).
    • The “Close Quote” button allows you to close an activated Quote record.  During this process you can request a revision be created which would give you the same end result as if you had pressed the Revise button.  If you don’t chose to have a revision created you are effectively just cancelling/deactivating the quote and you get the option of closing the Opportunity as Lost at the same time.  This whole experience feels clunky and unnecessarily complex, the button should just set the Quote status to inactive/cancelled and offer nothing else.
    • To progress an activated Quote and indicate it has been accepted you click the “Create Order” button.  A sub-screen is popped and you are given the option to close the related Opportunity as Won at the same time.   This screen will close the Quote as Won, create an Order record based on the Quote and optionally close the related Opportunity as Won.  If you opt for the Opportunity closure to happen and the Opportunity has other open Quotes attached to it they will be automatically cancelled (the concept being that these were alternative proposals and the customer went with the Quote that you have just closed so these other Quotes are no longer of interest).

    Orders

    • Order records are parented by Quote and Opportunity records, these lookup fields are placed low on the Order form by default.  You can create Orders from Open Opportunities but I get the feeling you are really expected to follow the “Opportunity —> Quote –> Order” process flow.
    • The Order Pricing is locked initially.  If the pricing changes on the Price List and you click the Recalculate button the Order pricing will not update.   If however you click the “Use Current Pricing” button the Order will be unlocked and the unit prices will be refreshed from the current pricing on the Price List.  Whilst unlocked the Recalculate button will refresh the pricing from the Price List.
    • The “Get Products” and “Lookup Address” buttons are here and work the same way.
    • To progress the Order you have 3 options:  the “Create Invoice” button, the “Fulfill Order” button or the “Cancel Order” button.
    • The “Fulfill Order” button essentially closes the Order and updates the status to “Fulfilled” – i.e. we have shipped the order to the customer.
    • The “Create Invoice” button creates an Invoice record.  It does not change the status of the Order.  Invoicing is treated as parallel process to Order Fulfilment, you can generate the Invoice before or after Fulfilment.
    • The “Cancel Order” button changes the Order status to Cancelled but does nothing else.  If an Invoice has been generated it remains active and the parent Quote record remains Won.

    Invoices

    • Pretty much everything said for Orders applies for Invoices, the same set of buttons are available to update the Product details or Pricing or to cancel the Invoice.
    • The last step of the sale process in CRM is to click the Invoice Paid button, which closes the Invoice and updates the Status.

    The CRM functionality gets weaker as you progress through the sales process into Order and Invoice.  You really are crossing across into ERP territory by this point and I think these CRM entities really exist as placeholders to represent ERP Order and Invoice data that is expected to be fed to CRM by integrations you implement.

    There are sample SSRS reports for Order and Invoice available on each form which you can customise to your requirements. 

    Noticeably absent from this whole process is tax calculations.   This is further evidence that Microsoft have not tried to create ERP competing sales order processing functionality.

     

    Sales Territories

    • Sales Territories seem to have no effect in CRM, they exist to supply a data structure that you may chose to utilise in your reports and workflows.  Or you can happily ignore Sales Territories (I’ve never used them on a CRM project).  
    • Each user can be associated to a single Territory
    • Each Territory can be assigned a Manager
    • Account records can be associated to a single Territory

    Sales Quotas

    • Sales Quotas are a deprecated feature from CRM 4.0 that is still around in CRM 2011 but not expected to be around in the next version.  The Goals feature introduced in CRM 2011 is meant to be used instead.
    • Whilst you will see Sales Quotas appear on the menu in CRM 2011 the feature is not usable.  I guess Microsoft have retained a read only view of this data to allow those that were using it to move over to Goals once they upgraded.

    Sales Literature

    • The Sales Literature feature in Microsoft CRM allows you to use CRM as Document/File repository.
    • The Sales Literature record itself is a header record – maybe you would create one per Product.  Beneath that header record you create Sales Attachment records.  Each one of these has a file attachment and metadata that describes that document.   Search keywords can be specified here but CRM never offers a useful way of searching against these.
    • Instead of creating Sales Attachment records under a Sales Literature record you could implement Microsoft CRM’s native integration to SharePoint and enable a SharePoint document library under each Sales Literature header and have the documents stored in SharePoint rather than CRM.  If you wanted to use SharePoint though maybe don’t even bother with the Sales Literature record, just enable a SharePoint site for each Product record.
    • Sales Literature records can be associated to Products such that when looking up or drilling down on a Product in CRM you can easily access the Product’s Sales Literature.  It’s a bit ‘clicky’ though.
    • One nice thing you can do from the Sales Literature form is you can click a button and an CRM email form will be launched with all of the Sales Attachments added as Attachments.
    • Sales Literature can also be associated with Competitor records and then easily accessed from the Competitor form.

    Competitors

    • Competitor records in CRM are used to represent those organisations you compete with.  You can store some competitive intel on these records for your sales force to refer to.  You can associate Products from your Product Catalog to Competitors (not sure why you would want to, I guess the idea is to indicate which of your products each of your Competitors also sells).
    • Open Opportunities can be associated to one or more Competitors.  This has no real effect except for providing a description of the competitive landscape, something someone could refer to or some boffin could write reports about.
    • As you close an Opportunity as Lost you can select the Competitor you lost to.  This is quite valuable and a feature I always encourage customers to use.