Oct 31, 2012

Sample Plug-in: State change

It is important to catch the action when a state change occurs for a record. What we are referring here is the setting of Status (statecode) and Status Reason (statuscode). They are native CRM fields and they work as combinations. These values even determine whether a record is active or inactive. Here you can see full list of those codes for native CRM entities.

Though, those fields appear normal, one should not attempt to update them using normal update method as any other field. They are special fields and they are changed through state change method only.

What is important is, we have separate messages to capture those state changes and we have to write the plug-in code accordingly. Please refer below code to understand how we grab those codes so that we are ready to implement the logic.

Please note state.Value and status.Value we get in this code is the new values after the set state operation. We may capture whatever the status change we are interested in.

using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.ServiceModel;

namespace TestCompany.CRM.Plugin
{
 public class officeSetState : IPlugin
 {
   public void Execute(IServiceProvider serviceProvider)
   {
     IPluginExecutionContext context;
     IOrganizationServiceFactory factory;
     IOrganizationService service;

     try
     {
       context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
       factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
       service = factory.CreateOrganizationService(context.UserId);

       if ((context.InputParameters.Contains("EntityMoniker")) && (context.InputParameters["EntityMoniker"] is EntityReference))
       {
        var targetEntity = (EntityReference)context.InputParameters["EntityMoniker"];
        var state = (OptionSetValue)context.InputParameters["State"];
        var status = (OptionSetValue)context.InputParameters["Status"];

        if (targetEntity.LogicalName != "new_office")
        { return; }
                    
         // Set State Logic
         // state.Value gives state code
         // status.Value gives status code

        }
      }
      catch (FaultException<OrganizationServiceFault> e)
      {
        throw e;
      }
      finally
      {
        service = null;
        factory = null;
        context = null;
      }
    }
  }
}

Tricky part lies here. When registering the plug-in we need to have steps for both SetState and SetStateDyanamicEntity messages.


Related posts;
Sample Plug-in: Delete
Sample Plug-in: Compare Pre and Post images on Update
Sample Plug-in code: Create and Update
Retrieve attributes of entity object

Sample Plug-in: Compare Pre and Post images on Update

We often use Update message to execute something after identifying whether a particular value is changed from A to B. Typically, we might need to handle some logic to be run upon state change which is defined as a custom field (actually an optionsetvalue). In this case, we need to implement a post update plug-in with two images. Here images are snapshots of the entity in pre/ post execution which enables us to compare some values.

Scenario I am explaining got a custom field called new_officestatus which holds the status of office (new_office entity). It says whether a given office is a main, regional or sub office.


Suppose we need to do something when an office is converted from Sub to Regional.  What we going to do is compare the values of the status in each update action. Below are the optionsetvalues;

Regional - 100000001
Sub – 100000002
Main – 100000003

If we find Pre image with 100000002 and Post image with 100000001, it is the exact time that a sub office is converted to a regional one, which we need to execute our custom logic. Below code shows how it’s being done programmatically.

using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.ServiceModel;

namespace TestCompany.CRM.Plugin
{
public class officeUpdate : IPlugin
 {
  public void Execute(IServiceProvider serviceProvider)
  {
   IPluginExecutionContext context;
   IOrganizationServiceFactory factory;
   IOrganizationService service;
   Entity PreImage;
   Entity PostImage;

   try
   {
     context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
     factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
     service = factory.CreateOrganizationService(context.UserId);

     PreImage = (Entity)context.PreEntityImages["PreUpdateImage"];
     PostImage = (Entity)context.PostEntityImages["PostUpdateImage"];

     int _preOfficestatusVal = 0;
     int _postOfficestatusVal = 0;

     if (PreImage.Contains("new_officestatus"))
     { _preOfficestatusVal = ((OptionSetValue)PreImage["new_officestatus"]).Value; }
     if (PostImage.Contains("new_officestatus"))
     { _postOfficestatusVal = ((OptionSetValue)PostImage["new_officestatus"]).Value; }

     if ((_preOfficestatusVal == 100000002) && (_postOfficestatusVal == 100000001))
     {
        // Logic for - Sub converted to Regional
     }

    }
    catch (FaultException<OrganizationServiceFault> e)
    {
      throw e;
    }
    finally
    {
      service = null;
      factory = null;
      context = null;
      PreImage = null;
      PostImage = null;
    }
  }
 }
}

Now we will see plug-in registration. Here, we register two images for Pre and Post stages. They have the same name as images we read from the context in the code.


Related posts;
Sample Plug-in: Delete
Sample Plug-in: State change
Sample Plug-in code: Create and Update
Retrieve attributes of entity object

Oct 30, 2012

Sample Plug-in code: Create and Update

This is a sample code which can be used for create and update of a record. Here I have used a custom entity called new_office.

using System;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System.ServiceModel;

namespace TestCompany.CRM.Plugin
{
public class officePreCreate : IPlugin
{
  public void Execute(IServiceProvider serviceProvider)
  {
    IPluginExecutionContext context;
    IOrganizationServiceFactory factory;
    IOrganizationService service;
    Entity TargetEnt;

    try
    {
     context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
     if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
     {
       TargetEnt = (Entity)context.InputParameters["Target"];
       if (TargetEnt.LogicalName != "new_office")
           return;

       factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
       service = factory.CreateOrganizationService(context.UserId);

       // Do the logic as required

      }
     }
     catch (FaultException<OrganizationServiceFault> e)
     {
       throw e;
     }
     finally
     {
       service = null;
       factory = null;
       context = null;
       TargetEnt = null;
     }
  }
}
}

Create message

In both Pre and Post stages we have all the attributes of the record to be used in our logic. We got to select either pre or post stages depending on business logic.

In pre stage (both Create and Update) we have an extra facility of changing attributes before Creating / Updating the record. For example, if I need to add some postfix to a string fields, I can do as below;

if (TargetEnt.Contains("new_name"))
{
    TargetEnt["new_name"] = TargetEnt.Attributes["new_name"] + " Pvt Ltd";
}

Consider the settings of the plug-in registration;

Pre Create;



Post Create;


Only difference would be the stage of execution.

Update message

When updating, in both Pre and Post stages, we get only modified attributes and primarkey. In Pre stage it is possible to amend those available values before updating. For example we can do the adding of postfix explained above if that field is available (i.e. modified) in target entity.

Consider the settings of the plug-in registration;

Pre Update;


Post Update;


Now message is Update instead of Create and stages are varied as Pre and Post.

Related posts;
Plug-in concerns: synchronous or asynchronous, transactional or not …
Sample Plug-in: Delete
Sample Plug-in: State change
Sample Plug-in: Compare Pre and Post images on Update
Retrieve attributes of entity object

Retrieve attributes of entity object

This is basic, but someone who is starting to code plug-ins (and custom codes) in CRM 2011 would be helped.

First visit this, which explains few basic differences of plug-in syntaxes in CRM 2011 with compared to earlier version.

Below are types we can initiate in our codes with their initial values.

Guid myGuid = Guid.Empty; // 00000000-0000-0000-0000-000000000000
String myString = String.Empty; // NULL
EntityReference myEntityReferance = new EntityReference(); //NULL
OptionSetValue myOptionSetValue = new OptionSetValue(); // 0
DateTime myDateTime = new DateTime(); //1/01/0001 12:00:00 AM
Decimal myDecimal = Decimal.Zero; // 0
Money myMoney = new Money(); // 0

Below are some simple ways of reading them from an entity object.

if (TargetEnt.Contains("new_officeid"))
{
myGuid = (Guid)TargetEnt.Attributes["new_officeid"];
}
if (TargetEnt.Contains("new_name"))
{
myString = TargetEnt.Attributes["new_name"].ToString();
}
if (TargetEnt.Contains("new_officestatus"))
{
myOptionSetValue = (OptionSetValue)TargetEnt["new_officestatus"];
}
if (TargetEnt.Contains("createdby"))
{
myEntityReferance = (EntityReference)TargetEnt["createdby"];
}
if (TargetEnt.Contains("createdon"))
{
myDateTime = (DateTime)TargetEnt["createdon"];
}
if (TargetEnt.Contains("new_revenue"))
{
myDecimal = (Decimal)TargetEnt["new_revenue"];
}
if (TargetEnt.Contains("new_cost"))
{
myMoney = (Money)TargetEnt["new_cost"];
}

Oct 21, 2012

Rule definitions to enable buttons for All RECORDS or SELECTED REDCORDS

This is a handy way of enabling the buttons either for “all records” or “selected once”. I will explain a scenario as below;

Consider an action you need to do against the records populated in a grid/subgrid. Typically we may need to do the action in two ways;

1) We may need to select records and perform the action
2) We may need to perform action for all the records

My solution is to introduce two custom buttons with two rule definitions that work well in terms of useability engineering aspects.

When loading the grid you will see only “All records” button enabled as below. (Pic. A). Idea is, if user interested in executing the action against all record, nothing to worry, just press it.


Suppose, we need to cherry pick the records. Now as soon as we start to select records, we get the view of this. (Pic. B).



Now only “Selected records” button is enabled. There is no confusion; one can execute the action only for selected items. If user deselects everything again, ribbon buttons will get changed to previous state again. (Pic. A)

Now we will see the simple way of defining the enabling rules for both buttons.

<RuleDefinitions>
  <TabDisplayRules />
  <DisplayRules />
  <EnableRules>
    <EnableRule Id="Mscrm.Cu_Selected">
      <SelectionCountRule 
        AppliesTo="SelectedEntity" Maximum="25" Minimum="1">
      </SelectionCountRule>
    </EnableRule>
    <EnableRule Id="Mscrm.Cu_SelectedAll">
      <SelectionCountRule 
        AppliesTo="SelectedEntity" Maximum="0" Minimum="0">
      </SelectionCountRule>
    </EnableRule>
  </EnableRules>
</RuleDefinitions>

Value 25 can be changed as you wish, which marks the maximum number you can select keeping the select button enabled.

Related articles;
How to proceed with All RECORDS (i.e. Scenario A) for Advanced Find results : Click here
How to proceed with SELECTED RECORDS (i.e. Scenario B) : Click here

Oct 14, 2012

Custom Group in Entity Ribbon

It is useful to know how to implement a new group in the ribbon and also to put buttons inside it. Before starting to explain an example I am happy to remind you a basic rule again.

Ribbon modifications can be done in main three ways to distinguish how they should appear in to user. They can be explained as below;

Mscrm.Form.<entityname>change appears when form is opened for selected record.
Mscrm.HomepageGrid.<entityname>change appears when grid is shown (multiple records)
Mscrm.SubGrid.<entityname> - change appears when records appear within a subgid of some other entity OR appears in the result pane of the advanced find

OK, I am here going to do the sample for Subgrid (so my tag naming format will be like Mscrm.SubGrid.<entityname>). In my example I am going to consider a custom entity called new_insurance.

My scenario is to give few buttons to renew insurance. Here I am just implementing one button to create a quote, but I put it in a Group called “Renewal Methods” so I can have other optional buttons for the same need.

This is the main custom action tag. Noticeably, it contains a button tag as we already know. So we can have many as required.

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Groups._children" 
              Sequence="110">
  <CommandUIDefinition>
    <Group Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
           Command="Mscrm.SubGrid.new_insurance.RenewalGroup.Command" 
           Title="Subscription Renewal" 
           Sequence="51" 
           Template="Mscrm.Templates.Flexible2">
      <Controls Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Controls">
        <Button Id="B_CUSTOM_QuoteCreate" 
                Command="Cmd_CUSTOM_QuoteCreate" 
                LabelText="Create Quote" 
                ToolTipTitle="Create Quotes" 
                ToolTipDescription="Create quotes for renewal subscriptions" 
                TemplateAlias="o1" 
                Image16by16="/_imgs/SFA/ReviseQuote_16.png" 
                Image32by32="/_imgs/SFA/ReviseQuote_32.png" />
      </Controls>
    </Group>
  </CommandUIDefinition>
</CustomAction>

Now we need to add two more custom action tags to define the appearance of the group we are introducing here.

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.MaxSize.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Scaling._children" 
              Sequence="120">
  <CommandUIDefinition>
    <MaxSize  Id="Mscrm.SubGrid.new_insurance.RenewalGroup.MaxSize" 
              GroupId="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
              Sequence="21" 
              Size="LargeLarge" />
  </CommandUIDefinition>
</CustomAction>

<CustomAction Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Popup.CustomAction" 
              Location="Mscrm.SubGrid.new_insurance.MainTab.Scaling._children" 
              Sequence="140">
  <CommandUIDefinition>
    <Scale Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Popup.1" 
           GroupId="Mscrm.SubGrid.new_insurance.RenewalGroup.Group" 
           Sequence="85" 
           Size="Popup" />
  </CommandUIDefinition>
</CustomAction>

Now this is nothing new, we just define a JavaScript method to pass the selected ids when button is clicked.

<CommandDefinition Id="Cmd_CUSTOM_QuoteCreate">
  <EnableRules>
    <EnableRule Id="Mscrm.Cu_Selected" />
  </EnableRules>
  <DisplayRules />
  <Actions>
    <JavaScriptFunction Library="$webresource:new_createquote.js" FunctionName="CreateQuote">
      <CrmParameter Value="SelectedControlSelectedItemIds"></CrmParameter>
    </JavaScriptFunction>
  </Actions>
</CommandDefinition>

Then we define a command definition, actually without any rule since group is to be just viewed.

<CommandDefinition Id="Mscrm.SubGrid.new_insurance.RenewalGroup.Command">
  <EnableRules  />
  <DisplayRules />
  <Actions />
</CommandDefinition>

Then we define a command definition, actually without any rule since group is to be just viewed.
Finally we have an enable rule for the button which is quote smart. In fact, button get enabled only when at least one records selected and not more than 20 records selected. We change this as required.

<EnableRule Id="Mscrm.Cu_Selected">
  <SelectionCountRule 
    AppliesTo="SelectedEntity" Maximum="20" Minimum="1">
  </SelectionCountRule>
</EnableRule>

Once implement, we will see the subgrid Ribbon this;

Oct 4, 2012

Advanced find – Select all the records of all the pages

Ribbon of advanced find result view

 
Ribbon of the result pane of advanced find view is same as Subgrid ribbon. Yep it is! So whatever the ribbon modifications you do with the format of  “Mscrm.SubGrid.<entityname>” is being applied for this ribbon. So you are free to do anything with any custom button by executing a Javascript as I explained in my previous post. Check it here.

Now we know, we can pass different parameters to our method, but obviously, favourite would be the passing of Ids of selected records. So we are good to do any operation for those records.

Reading the current grid VS reading the full result set

Anyway, none of these parameters leads us to read all the records of all the pages of the result. Our operations are restricted to current grid. Current grid could hold maximum records of 250, with least 25, depending on your settings.


If our result consists of more records and we need to do a batch operation for all of them we are not helped. One approach would be to save the view after selecting the criteria and again read the relevant fetch from SavedQueryBase. Problem of this approach is one has to save it manually with a predetermined name. (Name is to be used when querying by the programme)

Now this is a way of reading the relevant Fetch XML without saving, from the result pane. I urge this is an unsupported method, but it works.

var _XML = document.getElementById("fetchXml");
alert(_XML.value);

Now we have the fetch used to read the data for advanced find, so we are ready to do any operation for entire result set.