Thursday 7 November 2013

Migrating from Salesforce to Dynamics CRM 2011 (and 2013) – Top 3 Tips

Making the switch from Salesforce to CRM is not without its pitfalls, but with the right planning and preparation it can be made a much smoother process. Using past experience of Salesforce to CRM migrations, I have put together my top 3 tips to aid in a successful migration:

Tip 1 – Salesforce dropdown lists vs. CRM options sets
Within Salesforce, dropdown lists have the notion of ‘active’ and ‘inactive’ drop down list values. This notion does not exist in CRM, so planning must include detailed dropdown list to option set value mapping. If you need the same values from Salesforce in CRM you will find the lists very long, and once the client logs in they will say “We did not have this many list values before”. This is because you now have all the inactive dropdown list values from Salesforce in CRM. It must be decided if the older inactive dropdown list items should map to a more generic option set value of “Legacy” or similar, or use JavaScript to hide the values on the form. The latter approach does involve custom JavaScript development so of course is best avoided, if business rules will allow.
Tip 2 – Salesforce “Record Types”
Within Salesforce there is the notion of a ‘record type’, which drives a lot of form functionality, and also subsequent business rules. Let’s say you had an account that could be a type of “Supplier”, or type of “Client”. When creating a record in Salesforce it will ask which type you would like the account to be, and based on the selection you will be presented with a different form, and also different rules applied to the form. Again, this notion does not exist in CRM so it will either have to be replicated via customisation or planning must be done beforehand to agree on a uniform form layout for all record types.
Tip 3 – Salesforce Advanced currency management
The multi-currency functionality in Salesforce differs to CRM, and this must be taken into account. Salesforce will allow currency exchange rates to be set for individual fiscal periods, and those rates apply to all opportunities within that date range and currency. So let’s say you changed an exchange rate retrospectively for the Euro in a fiscal period last year: all the opportunities in Salesforce within that time period and set to Euro will reflect the new updated exchange rate. In CRM there is only one exchange rate – the current exchange rate and changing it will not updated previous past closed opportunities. Plan to have detailed discussions with the client regarding this topic is it may be OK to use the CRM methodology for multi-currency. In many of the cases in my own personal experience the Salesforce method of currency management gave the client much better control over reporting figures, particularly for multi-national companies who report in one base currency, and even to the point where commission is based on the value of the exchange rate. In this scenario I have written a multi-currency engine for CRM that allows different exchange rates for fiscal periods. This is a large piece of work so best avoided if possible!
 
So, they are my top 3 tips to help in a successful migration from Salesforce to CRM. There will be other complications along the way as you might expect with a switch in application, however these three topics I have found to be the most problematic.
If you do need assistance with your Salesforce migration, drop me an email (my email address is on my blog profile page).

Sunday 14 April 2013

CRM 2011 Plugin to Update Case (Incident) Before Close

Sometimes it is necessary to update a property on a case just before it is closed in order to capture some important information, such as whether an SLA was met, or to set a resolved date for reporting purposes (if you don’t fancy grappling with case resolution records). Thankfully CRM 2011 provides a message to subscribe to implement this functionality. The “Close” message of “incident” is the message to take advantage of this, and running at “Pre Validation” stage of execution will ensure your changes get applied to the case before it is closed by CRM and no longer updateable. Here is a screenshot illustrating the appropriate message and step to subscribe to:
 
The one thing that you may not expect is the entity you will actually get passed within your plugin will not actually be incident (case) but will actually by Incident Resolution:
IPluginExecutionContext context = localContext.PluginExecutionContext;
Entity incidentResolution = (Entity)context.InputParameters["IncidentResolution"];
 
From this you can get the case to update using a standard retrieve, or your favourite method..:
                    Entity incident = localContext.OrganizationService.Retrieve("incident", ((EntityReference)incidentResolution["incidentid"]).Id, colSet);
 
You could also do things like check the properties of the case if you wanted to do some conditional updates, or go off and set something on the account record (if you couldn’t do it in a workflow of course) and so on and so on…
Now update the case, call an Org. Service update (pass in your case entity) and your case will be updated. Happy days.
Cheers,
Nick

Thursday 14 February 2013

Duplicate/Clone an entity in CRM 2011

The ability to clone much of the detail of the current record onto a new instance of that entity is a neat trick that can have lots of very useful applications. A couple of examples could be an opportunity renewal whereby you want to copy most of the original opportunity but maybe want to update a couple of dates to reflect the renewal; or where you want to duplicate a case instead of re-opening an old case, to track time spent more effectively.
There is both a coded and a codeless approach that can be utilised, each of which I will describe below, along with the benefits of each.

Codeless
The premise of the codeless approach is basically to use a self-referencing relationship and relationship mapping. The idea being that you would end up with a list of "child" entities on your parent entity and as child entities are added from the grid the relationship mappings would kick in and populate the data for you on the new child entity. This is the most basic form of cloning – but you can get a working model up and running in minutes. If the user experience is OK to your users then this is the way to go. Configurable and no C#/JavaScript in sight. The downside to this is the aforementioned user experience. Will users want to go to a grid and select "Add New Record"? Probably not. And also do you need some more "run-time" control over what values get set on the new entity? Relationship mapping is great but it is static, "Copy Field A from Parent Entity to Field A of Child Entity" and so on for each property to be mapped. There is no way to say "in a certain circumstance, actually don't just copy the field, but add some new data to it".

A detailed guide to this approach can be found here:
 
http://rc.crm.dynamics.com/RC/2011/en-us/online/5.1_CTP/cloneRecords.aspx
   

Coded
The coded approach offers some more flexibility, and involves adding a "Clone" button to your entity ribbon that calls a JavaScript method on your page. This method is great and a detailed write up is available here:

http://garethtuckercrm.com/2012/07/31/duplicate-record-button-using-jscript-in-microsoft-crm-2011/
   

However, this approach also has its drawbacks. We have now lost our link between the parent and child entities so we have lost that relationship (if we need that relationship of course). And we are now totally coded – there is no configuration available now, the person who wants to amend this function MUST be able to do a little JavaScript. There is also the fact that if you pass too many values to the new form you may end up going too long for a URL (OK you would have to pass a lot of values to get to this, but a few large notes fields would get you well on your way).
My solution to most of the drawbacks of each approach is to combine the two. So we use a self-referencing relationship and relationship mapping as described in the "Codeless" approach, but combine it with a "Clone" entity ribbon button and JavaScript function as described in the "Coded" approach. In order to do this we need to tweak the JavaScript function somewhat. What we are effectively doing is "fooling" CRM into thinking we have actually clicked the "Add New Record" from the related child entity grid ribbon, so we can inherit all of the benefits of the relationship mapping. At the same time we can also override a mapping value by passing the value to the opening form. So when the user clicks the button we can have some logic to say whether we want a particular value overridden, such as a type or a date field.
Here is the JavaScript to pass the parent entity to the new form in order to use field mapping:

       parameters["_CreateFromId"] = Xrm.Page.data.entity.getId();
    parameters["_CreateFromType"] = 3;
    parameters["etc"] = 3;

The _CreateFromId parameter is the ID of the parent record (which is the current record ID). The _CreateFromType is the EntityTypeCode of the current entity. In this case 3 for opportunity. The Entity Type Code list can be found here http://msdn.microsoft.com/en-us/library/bb887791.aspx). Here is a post that describes how to get the Entity Type Code at runtime for a custom entity: http://mileyja.blogspot.co.uk/2011/05/how-to-retrieve-metadata-for-entity.html. The etc parameter is again the Entity Type Code (what the etc stands for). Here it is in the full JavaScript function:

function openChildWindow()
{
    var parameters = {};
    parameters["_CreateFromId"] = Xrm.Page.data.entity.getId();
    parameters["_CreateFromType"] = 3;
    parameters["etc"] = 3;
    Xrm.Utility.openEntityForm("opportunity", null, parameters);
}

As mentioned before, we could override other values that would be handled by the relationship mapping simply by setting them here (as defined in the "Coded" approach above):
 
    parameters["name"] = "NEW NAME";

That would set the "name" property of the new cloned entity to "NEW NAME" regardless of the relationship mapping put in place.

One last thing to mention – you need to place the self-referential lookup on the form somewhere, and hide it.
 
That's about it for this one.
 
The above approaches will achieve cloning of entity level fields only; it will not be able to clone one to many records, such as products on an opportunity. If you need to do this then a plugin would be required to fire on create of the entity. From the plugin you could use the entity populated in the self-referential lookup to obtain all the one to many records and add them into the new entity.
 
Cheers,
Nick

Monday 11 February 2013

Connecting CRMSVCUTIL/External ASP.NET Application and CRM Online

The connection properties differ somewhat between connecting to CRM “On Premise” and CRM Online. The extra parameters required for CRM Online make up the difference, these being “Device ID” and “Device Password”. These are required as an extra security precaution for the online web services. So how do you get them? In order to get your very own device id and password you use the device registration executable in the SDK_Directory\Tools\deviceregistration\bin\debug directory (you will need to download the Dynamics CRM SDK and install it on your machine somewhere). You will need to open the deviceregistration Visual C# project and build it once in order to see the executable. Once this is done run the Device Registration exe from the command line, with the following parameters:
deviceregistration.exe /Operation:Register /Name:"123456789101" /Password:"123456789101"
The name and password are OPTIONAL. Here I am telling the device registration tool that I want my device name (ID) and password to specifically be this. If you leave them out it will generate a new device id/password automatically for you. Once it gives you these values these are what go into you connection string for your application. An example of this in a “CRM Online” connection string for an ASP.NET application:
<add name="Conn" connectionString="Url=https://CRM_ONLINE_URL; UserName=CRM_LOGIN(WLID/O365 ID); Password=XXXXX; Device ID=123456789101; Device Password=123456789101"/>

You do not however need the Device ID and Device Password for using CRMSVUTIL.
 
TROUBLESHOOTING
With regard to troubleshooting two issues I had and couldn’t find a resolution for online was an authentication issue: on CRMSVCUTIL the message was “Authentication Failure”: in this instance I had accidentally included the Device ID and Device Password parameters, and it doesn't like that. The other issue was a message from the ASP.NET website of “The device authentication failed!”. The second message is clearer as to what it has a problem with. At this point try running the Device Registration tool again with the Device ID/Password that you would like to use, and if you get a message along the lines of “device id already registered”, then this side of things is correct – your device is correctly registered. The issue in my case was the server time was out of sync with the CRM Online server. Mine was a full 10 minutes out, so setting it correctly and re-running the website resolved the issue.
Another issue I have seen is an incorrect locally stored device id profile. When you run the Device Registration tool it places an XML file with encrypted values in:
C:\%USERPROFILE%\LiveDeviceID
Delete the LiveDeviceID.xml file in here and re-run Device Registration, as per the instructions above.
Thanks,
Nick

Thursday 7 February 2013

ASP.NET Charts and CRM 2011 Using FetchXML

I was recently tasked with implementing some “dashboard” functionality within the standard Dynamics CRM 2011 Customer Portal to allow clients to see an overview of current cases, using various metrics. After thinking through the possibilities (Silverlight, JQuery, 3rd party controls) I decided to utilise ASP.NET Charts as a) they have been greatly improved in the latest versions of the .NET Framework and b) well, the standard dashboard in CRM uses them so they can’t be that bad! The initial plan was to have an ASP.NET Chart with a LINQ data source (pointing at CRM) however, due to some limitation in CRM for LINQ I had to resort to using FetchXML. The problem was around the “groupby” LINQ method not being supported by the CRM for LINQ libraries (at least not at the time of writing this). FetchXML however does have aggregate behaviour, so was an obvious backup plan.
Now, if you know ASP.NET and its data bound controls you will probably think there is no way you could have an EntityCollection (the result of performing a FetchXML operation) as a DataSource for an ASP:Chart (or ASP:Gridview for that matter). Well you would be right. The trick is to convert the resulting EntityCollection into a standard .NET Datatable, and then set that as the DataSource for the chart.
To summarise, this is the requirement: a pie chart in the Customer Portal showing the client an overview and summary of their current active cases, grouped by status (statuscode). There are more complex graphs and metrics required for the overall dashboard, but I have chosen the simplest one to demonstrate as part of this post.
The process for achieving this is as follows.
1. Add a chart to your aspx page (from the ToolBox), set its type to pie. If you are using Visual Studio 2010 or greater the chart controls will already be right there in the Toolbox:
 
If you are using an older version you may need to download and install the .NET Framework Chart Controls add on.
The mark up for the pie chart should be:
<asp:Chart ID="ChartActiveCasesByStatus" runat="server" Width="460px" >
            <Series>
                <asp:Series Name="Cases" YValueMembers="incidentcount" IsValueShownAsLabel="true" XValueMember="status"
                    IsVisibleInLegend="true" ChartType="Pie">
                </asp:Series>
     </Series>
            <ChartAreas>
                <asp:ChartArea Name="ChartArea1" Area3DStyle-Enable3D="false">
                    <AxisX LineColor="DarkGray">
                        <MajorGrid LineColor="LightGray" />
                    </AxisX>
                    <AxisY LineColor="DarkGray">
                        <MajorGrid LineColor="LightGray" />
                    </AxisY> 
<Area3DStyle Enable3D="false"></Area3DStyle>
                    <InnerPlotPosition Height="100" Width="100" />
                </asp:ChartArea>
            </ChartAreas>
            <Legends>
                <asp:Legend Title="Status">
                </asp:Legend>
            </Legends>
        </asp:Chart>

All of the elements within this mark-up can be tailored to suit the look and feel you require. This is just the standard look with a couple of minor tweaks to add a title to the legend, and also set the “InnerPlotPosition” to have the pie chart more central within the control.
2. Once the chart is in place the next thing that is required is the code to get the data we need from CRM in the right format, converted to a DataTable, and set as the DataSource for the chart (and then a DataBind() call on the chart of course). The code is remarkably simple:
string casesByStatus = @"
                <fetch distinct='false' mapping='logical' aggregate='true'>
                <entity name='incident'>
                <attribute name='incidentid' alias='incidentcount' aggregate='count'/>
                <attribute name='statuscode' groupby='true' alias='status' />
                <filter type='and'>
                <condition attribute='customerid' operator='eq' value='{" + Contact.ParentCustomerId.Id.ToString() + "}' />" +
                "<condition attribute='statecode' operator='eq' value='0' />" +
                "</filter> " +
                "</entity> " +
                "</fetch>";

            EntityCollection quotes_result = ServiceContext.RetrieveMultiple(new FetchExpression(casesByStatus));
            ChartActiveCasesByStatus.DataSource = ConvertToDataTable(quotes_result);
            ChartActiveCasesByStatus.DataBind();

We have our FetchXML string, retrieving all the active cases (incidents) for the logged in client, a count of them, grouped by statuscode.
The ConvertToDataTable(quotes_result) is where we call our method to convert our EntityCollection into a DataTable ready to be a valid DataSource for our chart. The code for this:
  private static DataTable ConvertToDataTable(EntityCollection entityCollection)
        {
            DataTable dt = new DataTable();
            int total = entityCollection.Entities.Count;
            for (int i = 0; i < total; i++)
            {
                DataRow row = dt.NewRow();
                Entity myEntity = (Entity)entityCollection.Entities[i];
                var keys = myEntity.Attributes.Keys;
                foreach (var key in keys)
                {
                    if (key.EndsWith("id"))
                        continue;
                    string columnName = key;
                    string value = GetValuefromAttribute(myEntity.Attributes[key], myEntity.FormattedValues.FirstOrDefault(y => y.Key == key));
                    if (dt.Columns.IndexOf(columnName) == -1)
                    {
                        dt.Columns.Add(key, Type.GetType("System.String"));
                    }
                    row[columnName] = value;
                }
                dt.Rows.Add(row);
            }
            return dt;
        }

        private static string GetValuefromAttribute(object unformattedAttribute, KeyValuePair<string, string> formattedAttribute)
        {
            if (formattedAttribute.Value == null)
                return GetValueFromCRMTypeAttribute(unformattedAttribute);
            else
            {
                return formattedAttribute.Value;
            }
        }

        private static string GetValueFromCRMTypeAttribute(object p)
        {
            if (p.ToString() == "Microsoft.Xrm.Sdk.OptionSetValue")
            {
                return ((OptionSetValue)p).Value.ToString();
            }
            if (p.ToString() == "Microsoft.Xrm.Sdk.Money")
            {
                return ((Money)p).Value.ToString();
            }

            if (p.ToString() == "Microsoft.Xrm.Sdk.EntityReference")

            {
                return ((Microsoft.Xrm.Sdk.EntityReference)p).Name;
            }

            if (p.ToString() == "Microsoft.Xrm.Sdk.AliasedValue")
            {
                return GetValueFromCRMTypeAttribute(((Microsoft.Xrm.Sdk.AliasedValue)p).Value);
            }
            else
            {
                return p.ToString();
            }
        }

This code goes through every Entity in the EntityCollection and generates a new row for each. Then a calculation is performed on each CRM data type within the entity to retrieve the value as a string and put it into a Column of the DataRow. The code was adapted to CRM 2011 from an existing forum post that showed how to do this in CRM 4.0 (http://www.codeproject.com/Articles/42334/Convert-BusinessEntityCollection-to-a-DataTable )

That’s it. This is what it looks like in the portal:

Pretty basic with regard to presentation, but this is where you can play with that mark-up, get the colour scheme you want, make it 3d etc. etc.
A fairly painless introduction to ASP.NET charts and CRM, but things do get a little hairier with line charts with multiple series & categories….maybe I will save that for another post.
Cheers,
Nick