Thursday, 27 June 2013

Enabling/Disabling "New Activity" ribbon button based on an attribute value of the record with a custom Javascript function and Ribbon Workbench (CRM 2011)

We have had the need to enable or disable the "New Activity" button on the ribbon of the Incident entity based on the value of a record attribute.
We were inspired from an answer on a similar question on the Microsoft social community. We have followed this solution as base and extended it with a custom Javascript function to achieve our purposes.
The question and answers mentioned above are at the following URL:

http://social.microsoft.com/Forums/en-US/a5a0666f-8a07-4b25-92a3-e36ce8861d04/crm-2011-how-to-disable-the-new-activity-ribbon-button-for-a-deactivated-custom-entity
This solution allow the enabling/disabling based on the status of the record (Active / Inactive).

First of all we have developed the Javascript function similar the following:
function addNewActivityEnableRule() {
    //Retrieve the parent window Page object
    var parentPage = document.parentWindow.parent.Xrm.Page;

    //Gets the desired attribute of the parent window page
    var parentPageAttribute = parentPage.getAttribute('parentPage_attributeName');

    //Check if attribute exists
    if (parentPageAttribute) {
      //Get the value of the attribute
        var parentPageAttributeValue = parentPageAttribute.getValue();

        //'value_for_enabling' : replace with the desired value
          (or extend the condition as needed)
        //Return true for the conditions where you want enable
          the ribbon button and false otherwise
        if (parentPageAttributeValue == 'value_for_enabling') {
            return true;
        } else {
            return false;
        }
    }
}

Our solution consists of the following steps:
1. Create a solution with the ‘Activity’ entity in it
2. Open the Solution in the Ribbon Workbench

3. Select 'Activity' entity (activitypointer)
4. Select the 'SubGrid' ribbon in the top right drop down
5. Select the 'New {0}' button and right-click -> Customise Command. Don’t select 'Customise Button'!


 
6. In the 'Solution Elements', expand the 'Display Rules' and for each display rule, set the 'IsCore' property to 'True' since we don’t want to customise these – only the command.
7. In the 'Solution Elements', expand the 'Commands' and select the 'Mscrm.NewRecordFromGrid' command and Right-Click ->'Edit Enable Rules'
8. Click 'Add New' and then 'Add Step'. Select a 'Custom Javascript Rule'

 

9. Set the properties:
      1. InvertResult: False
      2. Default: False


10. Provide the function name and the web resource script library where the function resides
11. Click 'Publish Solution'


Hope it can be useful
Happy CRM coding

Friday, 14 June 2013

Copy Rich Text Box field content into a text field with JavaScript (CRM 2011)

Richtextbox fields content (for example the body of an email activity) is a mix of text and tags: when copying its content into another CRM field of type Text, the destination field will contain also the tags.
Because the representation of a Textbox field is a simple string and it is not formatted as in the case of a Richtextbox, the result is that the text showed is similar to an HTML content.
This is not user friendly for CRM users, therefore we should remove all the tags and let only the original content; obviously, we will lose the formatting (bold, underline, etc...).
We can do that with JavaScript, using the regular expressions, as shown below:


var richTextBoxContent =
    Xrm.Page.getAttribute("richtextbox_attribute_name").getValue();
var richTextBoxContentStripped =
    richTextBoxContent.replace(/(<([^>]+)>)/ig, '');

Xrm.Page.getAttribute("text_attribute_name").setValue(richTextBoxContentStripped);


Hope it can be useful.
Happy CRM coding.

Saturday, 8 June 2013

Work with Assign SDK message in CRM 2011 plugin - manage logic based on the Assignee Team (CRM 2011)

In the following example I use the Assign message in CRM 2011 to manage some custom logic based on the assignee Team.
The plugin is registered in Pre-Operation stage on the Task entity and uses early-bound entity classes.
However it is trivial reuse the same logic on another type of entity, use late-bound entity classes, or operate on other type of assignee.

protected void ExecutePreTaskAssign(LocalPluginContext localContext)
{
    if (localContext == null)
    {
        throw new ArgumentNullException("localContext");
    }

    IPluginExecutionContext context = localContext.PluginExecutionContext;
    IOrganizationService service = localContext.OrganizationService;

    try
    {
        //Check if context contains the "Target" parameter and that it
          is an EntityReference
        if (context.InputParameters.Contains("Target") && 
                     context.InputParameters["Target"is EntityReference)
        {
            EntityReference targetEntity =    
                     (EntityReference)context.InputParameters["Target"];
            //Check if the entity type is Task
            if (targetEntity.LogicalName != "task")
            { return; }

            //Check if context contains the "Assignee" parameter
            if (context.InputParameters.Contains("Assignee"))
            {
                EntityReference assigneeRef = 
                       (EntityReference)context.InputParameters["Assignee"];
                //Check if the "Assignee" is a team
                if (assigneeRef.LogicalName == "team")
                {
                    Team team;
                    //Retrieve the team with all properties
                    team = service.Retrieve(assigneeRef.LogicalName, 
                        assigneeRef.Id, new ColumnSet(true)).ToEntity<Team>();

                    //Put your logic here based on the retrieved Team informations
                }
            }
        }
    }

    catch (Exception e)
    {
        throw new InvalidPluginExecutionException("An error occured for 
                Assign plugin " + e.Message + e.InnerException);
    }
}


Hope it can be useful.
Happy CRM coding.

Tuesday, 4 June 2013

Filter Option Set on values in a string (CRM 2011)

Sometimes it could be useful restricting the available options for an Option Set.
I have developed a function that accept as input the CRM option set control and a string.
This string parameter contains all string values that we want in the option set.
For reading simplicity I use to separate them with a character (';' for example) but technically it is not a need: the function searches every option value as a substring of it.
Another way to achieve this goal it could be to work with a list (an array) of accepted values, but I have found much easier and less complex the use of a string as "accepted values container".
 

function filterOptionSetValues(optionSetControl, filterValues) {
if (filterValues) {
var options = optionSetControl.getAttribute().getOptions(); //Get the list of values
optionSetControl.clearOptions(); //Clear Option set
for (var i = 0; i < options.length; i++) {
var find = filterValues.indexOf(options[i].text); //Search the string value in the string
if (find >= 0) {
if (parseInt(options[i].value) > 0)
{
//Build a new option and add to the control
var opt = new Option();
opt.text = options[i].text;
opt.value = options[i].value;
optionSetControl.addOption(opt);
}
}
}
}
}
 


Usage example:
var acceptedValues = "value1;value2;";
filterOptionSetValues(Xrm.Page.getControl("optionSet_name"), acceptedValues);


Hope it can be useful.
Happy CRM coding.

Monday, 3 June 2013

Retrieve current user info via JavaScript (CRM 2011)

I have had the need to retrieve different informations about the current user logged into CRM.
I have found this useful post that helped me to achieve my goal:

http://mahenderpal.wordpress.com/2011/05/11/get-current-user-id-and-name-in-javascript-ms-crm-2011/
I have then generalized the function in order to allow the retrieving of different user fields.
The function below accepts an array with the fields names we want to retrieve.


/*
Retrieve current user info.
fields is an array containing fields schema name to retrieve: if null --> all record fields will be retrieved
*/ 

function GetUserInfo(fields) {
var context;
var serverUrl;
var UserID;
var ODataPath;
var oDataQuery;
var retrievedUserInfo;
context = Xrm.Page.context;
serverUrl = context.getServerUrl();
UserID = context.getUserId();    

ODataPath = serverUrl + "/XRMServices/2011/OrganizationData.svc";
var retrieveUserReq = new XMLHttpRequest();
oDataQuery = ODataPath + "/SystemUserSet(guid'" + UserID + "')";
if (fields) {
oDataQuery = oDataQuery + "?$select=";
for (var i = 0; i < fields.length; i++) {
oDataQuery = oDataQuery + fields[i] + ",";
}        
oDataQuery = oDataQuery.substring(0, oDataQuery.length - 1); //Remove the last ","
}    
retrieveUserReq.open("GET", oDataQuery, false);
retrieveUserReq.setRequestHeader("Accept", "application/json");
retrieveUserReq.setRequestHeader("Content-Type", "application/json; charset=utf-8");
retrieveUserReq.onreadystatechange = function () {

if (retrieveUserReq.readyState == 4 /* complete */) {
if (retrieveUserReq.status == 200) {
retrievedUserInfo = JSON.parse(retrieveUserReq.responseText).d;
}
else {

//Handle errors
}
}
};
retrieveUserReq.send(); 
return retrievedUserInfo;

}


Hope it can be useful.
Happy coding.

Sunday, 2 June 2013

MS Dynamics CRM 2011 Dialogs - Features, Potentialities, Limits and Custom Solutions (CRM 2011)

With the new release of Microsoft Dynamics CRM, version 2011, was introduced a new concept: the Dialogs. Similar to the workflows, Dialogs are processes that guide users through a series of steps in an automatic and consistent way, but in a wizard-like style.

In some way we can assert that Dialogs are the synchronous and interactive version of workflows.

Dialogs are especially suitable in situations where a user needs to follow a consistent, rigid and standardized process that necessitates user input based on questions and answers and the flow decisions are made automatically upon them in the background; obviously, in this way, the organization’s productivity and its effectiveness are increased, with an important reduction in error possibility.

Imagine, for example, how dialogs could expedite phone calls in a call or customer care center. Highly skilled or technical staff need not be involved in a high percentage of cases. In fact, Dialogs can be used to guide less-experienced employees in troubleshooting, or in information gathering processes with minimal effort and training.

Furthermore, messages and services can be personalized, resulting in a major differentiator and a competitive advantage.
I've done a depth study and analysis of the Microsoft Dynamics CRM 2011 Dialogs. Dialogs offer a very powerful tool to design consistent, rigid, standardized and interactive processes but have some limitations that we examined and analyzed and that we discuss in this paper, along with some custom solutions we have designed to try to work around.

Components of Dialog Pages

Before we explain the layout components of dialogs, it's very important you to understand that page layouts are neither configurable nor customizable.

Dialogs that are created or updated outside of Microsoft Dynamics CRM by creating or updating the underlying XAML file are not supported in Microsoft Dynamics CRM.

Dialog pages components are:
-         Page Header
-         Prompt and Response
-         Tip Text
-         Comments

The following figure shows these sections in a dialog page:

Page Header

This section displays the dialog process name along with the page name. The messages in this section are configurable.

There is no automatic page number but it's a helpful practice to enter the page number as part of the title.

Prompt and Response

Each dialog page must have at least one prompt and response area. Pages can have more than one but using too many will mean the user must scroll through the pages and make it difficult to read.

Responses allow users to enter information but entries are not required for each prompt.

Configurable messages

Through some experimentation, I have found a solution to make prompt messages (and tips) configurable, avoiding the user to must to work directly on the dialog definition to change them.

The solution is based upon the use of the dynamic values and the CRM custom entities and it is explained below.

1.    Create a custom entity in MS Dynamics CRM with a number of fields depending on how many custom prompt and tips messages we need. The type of these fields must, obviously, to be "text" and the length depends from what is predicted may be the maximum message length.

2.    Consider that we need to create a custom entity for each process and must to exist one and only one record of this entity that contains all the needed messages.

3.    Then, create a one to many relationship between this entity and the entity involved in the dialog process.

4.    Next, create a record of the custom entity entering all the messages in the appropriate fields.

5.    At this point, all records of the entity involved in the dialog process must be associated with the newly created record. Develop a plugin to make that association for every new record created. For those that already exist in the system, instead of doing this association manually, it is better to develop an automated process.

Now it's possible to enter dynamic value for each prompt message, retrieving it from the appropriate record field and dialog message are configurable, in fact, it's sufficient for a user update the appropriate message from the configuration record created to modify a prompt or a tip message in a dialog page without the need to change it directly into the dialog definition. This solution also works for page titles.

Tip Text

This section is useful to display instructions that are not included in the prompt message. Every prompt can have a separate tip associated to it and it will be displayed when the user enter with the mouse on it.

Comments

This area it is very useful because entered information persist throughout the dialog process, making it possible to write information on one page that is needed in another subsequent.

Buttons

Buttons displayed in each dialog page are:
-         Help – Leads the user to the Microsoft Dynamics CRM help page.
-         Summary – Displays the dialog session.
-         Previous – Returns the user to the previous dialog page. This option is only available if the user has proceeded to another page next the first.
-         Next – Advances the user to the next dialog page. This option is hidden when the user has proceeded to the last page of the dialog session.
-         Finish - Exits the dialog pages. This option only displays when the user has reached the final step of the dialog session.
-         Cancel - Cancels the dialog session before the user has reached the end of the dialog process. When this button is selected, the dialog session will be closed with a Status Reason of Canceled.

Important: it’s not possible to neither customize these buttons nor change their behavior programmatically (i.e.: show/hide).

Starting Dialog Processes

A dialog process can be started in one of the following ways:
1.    Manually.
2.    Automatically, as a child process of another dialog.
3.    Calling by its URL.

It’s important to you to understand that, due to its interactive nature, it's neither contemplated a way to start a dialog process using the SDK nor from another kind of process such as a workflow.

Due to the interactive nature of the dialog process, you cannot run a dialog using the Microsoft Dynamics CRM SDK. A dialog can only be run through the Microsoft Dynamics CRM Web application and is not supported in Microsoft Dynamics CRM for Microsoft Office Outlook with Offline Access.

For the same reasons a Dialog cannot be triggered by events; it always runs on-demand. Dialogs always require user interaction to complete. Furthermore Dialogs can only be run on one record at a time.

All dialog processes are associated with a URL, hence you can call them by using its URL.

To open a dialog through its URL you need the following:
1.    The unique identifier for the dialog.
2.    The logical name for the entity the dialog is created for.
3.    The unique identifier for the record you want to have the dialog run against.

The URL is formatted as below:
[organization url]/cs/dialog/rundialog.aspx?
DialogId=[dialog unique identifier]&
EntityName=[entity logical name]&
ObjectId=[unique identifier for the record]

To get the unique identifier for the dialog, navigate to Settings, and in the Process Center group, select Processes. Right click the dialog, and in the context menu, select Copy a Link.

This feature is useful because it allows to externally calling the dialog process. To retrieve the needed information to build the URL from CRM it is necessary to develop a Workflow utility, because creating a link to a Microsoft Dynamics CRM record is not available out of the box.

Remember that there is no a way to pass parameters to the dialog process not even through its URL.

Steps

The following options are provided natively by Microsoft Dynamics CRM for setting up dialog process steps:

1.    Stage
2.    Page
3.    Prompt and Response
4.    Check Condition
5.    Conditional Branch
6.    Default Action
7.    Query CRM Data
8.    Assign Value
9.    Create Record
10. Update Record
11. Assign Record
12. Send E-Mail
13. Start Child Workflow
14. Link Child Dialog
15. Change Status
16. Stop Dialog

Most of these actions are self-explanatory and well documented, but I want discuss "Link Child Dialog" and "Start Child Workflow".

Link Child Dialog

A dialog process can call a child dialog. The child dialog must be associated with the primary entity of the dialog process or a related entity. The "Link Child Dialog" action allows you to pass data by using input arguments. Note again that input arguments and parameters are not available for the primary dialog process and the child dialog must to be marked as such during the creation step.

There is a big limit to consider:
Link child dialog cannot be an intermediate step.

It means that, in this release, "Link Child Dialog" must to be the last step of the process. Furthermore, it can be only one child dialog per dialog process.

An important feature is the ability to create a recursive process using "Link Child Dialog" step. I used this feature to try to achieve a solution to a problem that I'll show later.

Start Child Workflow

Similarly to "Link Child Dialog" action, only workflow processes that are configured to run as child processes can be run from a dialog session and, furthermore, it must be associated to the primary or a related entity of the dialog process.

This is an important feature that allows us to start some processes in the background, passing them any needed data as input parameters.

It's possible, for example, collect some data from the dialog and then start some processes that will operate on that data.

Remember that unlike the dialogs, workflows are asynchronous processes and hence, they run separate from the caller dialog. Therefore, never develop a dialog step conditioned to a workflow output.

Loop “virtual” action

A loop action is not available for the dialog processes steps. That means that you cannot use a "while-action" to do the same interactive actions repetitively.

However it's possible to simulate a loop by using recursion on child dialog. Simply call "Link Child Dialog" to itself until the termination condition is reached.

This could be a very useful feature but, unfortunately, as I mentioned early, there is the one child per process limitation and this must be the last step of the process.

I used this feature to solve a problem that I will show later but these limitations make it less flexible and thus poorly serviceable.

Custom Workflow Activity

A very powerful feature is the ability to extend the native actions of the dialogs with custom workflow activities.

Important to know: The only one supported framework is Windows Workflow Foundation 4.0, therefore custom activities must be developed using this and not the 3.5 version.

Writing custom workflow activities gives you the power to develop all the needed business logic by using the SDK. By properly using InArgument and OutArgument you can pass data to the activities and receive data from them.

To develop custom workflow activities and make them available to Dynamics CRM Dialogs, you must to create an "Activity Library" project within Visual Studio 2010, then check that the framework version is 4.0 and that the framework-type is “.NET framework” and not “.NET framework client profile” (often it is the default setting).

The following assemblies are needed hence add a reference to them:
·         microsoft.xrm.sdk.dll
·         microsoft.xrm.sdk.workflow.dll
These are distributed with the Microsoft Dynamics CRM 2011 SDK.

Each custom workflow activity developed must derive from System.Activities.CodeActivity and require the following namespaces:
·         Microsoft.Xrm.Sdk
·         Microsoft.Xrm.Sdk.Workflow

Each parameter needed as input must:
1.    Be an InArgument<T>, where T is the type.
2.    Use [Input(InputName)] attribute, where "InputName" is a string and it is the name displayed in the dialog step properties window.
3.    Use [Default("DefaultValue")] attribute, where "DefaultValue" is the default value that we want for the parameter.

Although the default value is not required, it's better to use it, even empty, because the absence of it could cause problems during the library registration process.

Each parameter needed as output must:
1.    Be an OutArgument<T>, where T is the type.
2.    Use [Output(OutputName)] attribute, where "OutputName" is a string and it is the name displayed in the dialog step properties window.

After that, you must to override the Execute() method in which you write your business logic.

Below a skeleton of a Custom Workflow Activity that follow the above rules.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Activities;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Workflow;

namespace CustomWorkflowActivitiesNamespace
{
    public sealed class SkeletonCustomActivity : CodeActivity
    {
        [Input("Input Argument 1")]
        [Default("")]
        public InArgument<string> InputArgument1 { get; set; }

        [Input("Input Argument 2")]
        [Default("")]
        public InArgument<string> InputArgument2 { get; set; }

        [Output("Output Argument")]
        public OutArgument<bool> OutputArgument { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            //Put your logic here
        }
    }
}

Input Validation

Unfortunately, there is no a way to validate the input data entered by a user native in the dialogs processes.

In an attempt to find a solution to this problem, I have tried to exploit all the features available.

I have designed and experimented two solutions but, unluckily, both have some limits
1.    Using of custom workflow activity
2.    Using of custom workflow activity, Link Child Dialog action and recursion

Exploiting the advantages and the features of the custom workflow activity, I have designed a generic activity that carries out data validation based upon regular expressions. With the regular expressions we can make a different kind of validation, covering a high percentage of situations and therefore the module is highly reusable.

The code is:

public sealed class RegularExpressionValidator : CodeActivity
{
    [Input("String to Validate")]
    [Default("")]
    [RequiredArgument]
    public InArgument<string> StringToValidate { get; set; }

    [Input("Regular Expression")]
    [Default("")]
    public InArgument<string> RegularExpression { get; set; }

    [Output("Input String is Valid")]
    public OutArgument<bool> InputStringIsValid { get; set; }

    protected override void Execute(CodeActivityContext context)
    {
        bool _inputStringIsValid = Regex.IsMatch(StringToValidate.Get(context),RegularExpression.Get(context));

        InputStringIsValid.Set(context, _inputStringIsValid);
    }
}
Validation using Custom Workflow Activity

By using a custom workflow activity that performs the validation of an input (such as that above), we insert this after the "prompt and response" step that needs a validation, passing the user input data as input argument. Then execute the business logic to perform the validation and retrieve the result boolean value returned as output argument.

Next we use that value in a check condition step and, if the input was invalid, display a message error to the user in the next page.

As I mentioned early, there is no way to inhibit the dialog buttons, therefore, with this solution you can only inform the user about the invalid data entered, but you cannot prevent him from going to the next step, therefore, it's up to the user to go to the previous page and correct the error.

Validation using Custom Workflow Activity, Link Child Dialog and Recursion


This solution is based on the features, concepts and custom solutions described above.

Conceptually, you use a custom activity to perform data validation and the recursion to simulate a loop. In this "virtual loop" you are asking the user to input data, check its validity and proceed to next step or display an error message and asking to reenter the correct data, according to the result of the validation check.

Below a schema to set up this solution:
1.    Create a Dialog and mark it as a Child.
2.    In the dialog created in step 1 insert a step to ask for user data input.
3.    Insert a next step with the data validation activity.
4.    Insert a Check Condition to verify the validation result.
a.    If the data are not valid recursively call itself.
b.    If the data are valid add a Stop Dialog action to terminate recursion.
As already explained, use of Link Child Dialog action has two big limitations:

1.    There is a maximum of one "Link Child Dialog" action per dialog process.
2.    This action must be the last of the process.
These restrictions have strong implications:
1.    All the validation logic must be done in one unique "Link Child Dialog" action.
2.    It must be the last step of the dialog process.
Although it could be technically achievable in many casuistries, it forces the functional process to be adapted to those conditions and it's unacceptable: the technology must to adapt to the functional requisites and the processes and not the vice versa.

External information as necessary input for the process

You might encounter situations in which there is the need of some external information already available at the beginning of a dialog process.

Although there is no a way to pass arguments, you can work around this limit using custom workflow activities. You can easily develop an activity that retrieves all the needed information and insert it as first step of the process, before every other prompt and response.

Obviously, this workaround works well also for every intermediate process step where there is the need of external information, meaning not provided by the user.

Monitoring dialog processes

A very powerful and useful feature provided by Microsoft Dynamics CRM 2011 is the ability to monitor the dialog processes.

The dialog process record contains a Dialog Sessions link that lists all executed instances of that process in the system with their status.

Status can be one of the following:
·         In Progress
·         Canceled
·         Completed

By opening a dialog session record, become available all detailed information including the Summary that show you all the prompt and response messages with the actual values eventually retrieved from the message configuration record discussed previously.

The dialog sessions historical logging feature of MS Dynamics CRM is very useful not only for the developers but also for the final users because it allow him to review a session and even to make some analysis on the functional flow.


Hope it can be useful.
Happy CRM coding