Saturday, 1 December 2012

Dynamics CRM 2011 - Export Report data to Excel - Data type issues

One of my customers has developed a custom report via report wizard in Dynamics CRM 2011 online. She had exported the report data to excel. Surprisingly, the currency data was exported in text format and hence she was unable to perform arithmetic calculation on that. She tried to convert them to numbers in excel but no success. So, she knocked on my door and explained me the problem.

After doing some research I found that this is a defect in Dynamics CRM 2011. You can refer the same on Connect site with help of below URL

https://connect.microsoft.com/dynamicssuggestions/feedback/details/661931/export-report-to-excel-data-type-issue

Workaround

Follow the below steps to convert the text data to numbers

1. Insert a new column beside the currency data column

2. Apply below formula in newly created column besides every data row

=VALUE(RIGHT(G2,LEN(G2)-2))

Here in above example I have used cell no as G2. You need to use your data column cell positions.

Reference

http://social.microsoft.com/Forums/is/crm/thread/43d38c71-722a-4a65-8e18-340a01c0d31b

I hope this will be helpful.

Friday, 23 November 2012

Dynamics CRM 2011 - Creating an e-mail activity with PDF format custom SSRS report as an attachment

Last updated – 10th June 2016

This blog post uses SDK.SOAP.js to perform all CRM web service calls.
Please refer following link to know more about the SDK.SOAP.js.
http://ankit.inkeysolutions.com/2014/10/sdksoapjs.html


Recently, I came across a requirement where I had to create a functionality that will create an email activity on “Order” entity that would be having a custom report in PDF format as an attachment. This functionality needs to be executed on a ribbon button click. I couldn’t find any complete example that covers all these functionalities. Hence, in this post, I will be sharing the complete solution to generate PDF file from a custom SSRS report and attach the same to newly created email activity.

Please follow below steps to achieve this functionality:

1) Variable initialization and EmailReport(), a starting point, this method needs be called via JavaScript code.
2) Creating an email activity for the “Order” entity.
3) On this step, we will fetch the SSRS report's GUID by using report name.
4) Creating an attachment for the email activity and binding the report in a PDF format as attachment.

Variable initialization and EmailReport() method that can be called via JavaScript code. – Step 1

This code initializes the variables, which are required in next steps of this post. Plus, it defines two JavaScript methods,


var reportName = "SampleReport"; //Please specify your report name.
var reportId = null;
var fileName = "PDF01"; //Please specify a file which you want to save.
var fromFieldId = null;
var fromFieldEntityName = null;
var toFieldId = null;
var toFieldEntityName = null;
var emailId = null;

//This function is need to be called from action side e.g. Ribbon button click.
function EmailReport() {
  //This function does not work in add mode of form.
  var type = Xrm.Page.ui.getFormType();
  if (type != 1) {
    GetIds(); // Set ids in global variables.
    CreateEmail(); //Create Email
  }
}

//Gets the fromFieldId and toFieldEntityName used to set Email To & From fields
function GetIds() {
  fromFieldId = "00000000-0000-0000-0000-000000000000";//The Guid which needs to be set in form field.
  fromFieldEntityName = "systemuser";//Please specify entity name for which you have specified above Guid. Most probably it's systemuser.
  toFieldId = "00000000-0000-0000-0000-000000000000"; //The Guid which needs to be set in to field.
  toFieldEntityName = "contact";//Please specify entity name for which you have specified above Guid.
}


Creating an email activity for the “Order” entity – Step 2

With this step we will first create an email activity for the “Order” entity. When you create an email activity for an entity you must associate the entity and activity with either To, From or Regarding participation type. In this example the entity “Order” for which the email activity is created, is associated as Regarding in the email activity.

Now, we will have to set “To” and “From” fields of the email activity. The “To” and “From” are Activity parties associated with the email activity.

//Create Email and link it with Order as Reagrding field
function CreateEmail() {
  var id = Xrm.Page.data.entity.getId();
  id = id.replace('{', "");
  id = id.replace('}', "");
  var entityLogicalName = Xrm.Page.data.entity.getEntityName();
  var regardingObjectId = new Sdk.EntityReference(entityLogicalName, id);

  var email = new Sdk.Entity("email");
  email.addAttribute(new Sdk.String("subject", "Your Booking"));
  email.addAttribute(new Sdk.Lookup("regardingobjectid", regardingObjectId));
  var fromParties = PrepareActivityParty(fromFieldId, fromFieldEntityName);
  email.addAttribute(new Sdk.PartyList("from", fromParties));
  var toParties = PrepareActivityParty(toFieldId, toFieldEntityName);
  email.addAttribute(new Sdk.PartyList("to", toParties));
  Sdk.Async.create(email, EmailCallBack, function (error) { alert(error.message); });
}

//This method get entity's id and logical name and return entitycollection of it.
function PrepareActivityParty(partyId, partyEntityName) {
  var activityParty = new Sdk.Entity("activityparty");
  activityParty.addAttribute(new Sdk.Lookup("partyid", new Sdk.EntityReference(partyEntityName, partyId)));
  var activityParties = new Sdk.EntityCollection();
  activityParties.addEntity(activityParty);
  return activityParties;
}

// Email Call Back function
function EmailCallBack(result) {
  emailId = result;
  GetReportId();
}
 

On this step, we will fetch the SSRS report's GUID by using report name. - Step 3

Use below code to fetch the SSRS report GUID using the SSRS report name.

//This method will get the reportId based on a report name

function GetReportId() {
  var columns = "reportid";
  var fetchQuery = new Sdk.Query.QueryByAttribute("report");
  fetchQuery.setColumnSet(columns);
  fetchQuery.addAttributeValue(new Sdk.String("name", reportName));
  Sdk.Async.retrieveMultiple(fetchQuery, RetrieveMultiple);
}

function RetrieveMultiple(entityCollection) {
  if (entityCollection.getEntities().getCount() > 0) {
    var entities = entityCollection.getEntities();
    var getAttribute = entities.getByIndex(0).getAttributes("reportid");
    if (getAttribute != null) {
      reportId = getAttribute.getValue();
    }
  }

  //get reporting session and use the params to convert a report in PDF
  var params = GetReportingSession();
  EncodePdf(params);
}


Creating an attachment for the email activity and binding the report in a PDF format as attachment - Step 4

Once we are done with creating an email activity and fetching the GUID value of the SSRS report in above steps, we will come to this step. Here it is creating an attachment for this newly created email activity.

The function GetReportingSession() gets the required details for converting a report into PDF. Using the function EncodePdf(), the report is converted into PDF format.

//Gets the report contents
function GetReportingSession() {

  var pth = Xrm.Page.context.getClientUrl() + "/CRMReports/rsviewer/reportviewer.aspx";
  var retrieveEntityReq = new XMLHttpRequest();
  var Id = Xrm.Page.data.entity.getId();

  retrieveEntityReq.open("POST", pth, false);
  retrieveEntityReq.setRequestHeader("Accept", "*/*");
  retrieveEntityReq.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  var orgUniqueName = Xrm.Page.context.getOrgUniqueName();
  var req = "id=%7B" + reportId + "%7D&uniquename=" + orgUniqueName + "&iscustomreport=true&reportName=" + reportName + "&isScheduledReport=false&p:salesorderid=" + Id + "&p:createdon=1/1/9999";
  retrieveEntityReq.send(req);

  var StartAfterComment = retrieveEntityReq.responseText.indexOf("e440105867d249ce8a45696677d42bcb") + 32;
  var x = retrieveEntityReq.responseText.lastIndexOf("ReportSession=");
  var ret = new Array();
  ret[0] = retrieveEntityReq.responseText.substr(x + 14, 24); //the session id
  x = retrieveEntityReq.responseText.lastIndexOf("ControlID=");
  ret[1] = retrieveEntityReq.responseText.substr(x + 10, 32); //the control id
  return ret;
}

function EncodePdf(params) {
  var retrieveEntityReq = new XMLHttpRequest();

  var pth = Xrm.Page.context.getClientUrl() + "/Reserved.ReportViewerWebControl.axd?ReportSession=" + params[0] + "&Culture=1033&CultureOverrides=True&UICulture=1033&UICultureOverrides=True&ReportStack=1&ControlID=" + params[1] + "&OpType=Export&FileName=Public&ContentDisposition=OnlyHtmlInline&Format=PDF";
  retrieveEntityReq.open('GET', pth, true);
  retrieveEntityReq.setRequestHeader("Accept", "*/*");
  retrieveEntityReq.responseType = "arraybuffer";

  retrieveEntityReq.onload = function (e) {
    if (this.status == 200) {
      var uInt8Array = new Uint8Array(this.response);
      var base64 = Encode64(uInt8Array);
      CreateEmailAttachment(base64);
    }
  };
  retrieveEntityReq.send();
}

var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
function Encode64(input) {
  var output = new StringMaker();
  var chr1, chr2, chr3;
  var enc1, enc2, enc3, enc4;
  var i = 0;

  while (i < input.length) {
    chr1 = input[i++];
    chr2 = input[i++];
    chr3 = input[i++];

    enc1 = chr1 >> 2;
    enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
    enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
    enc4 = chr3 & 63;

    if (isNaN(chr2)) {
      enc3 = enc4 = 64;
    } else if (isNaN(chr3)) {
      enc4 = 64;
    }
    output.append(keyStr.charAt(enc1) + keyStr.charAt(enc2) + keyStr.charAt(enc3) + keyStr.charAt(enc4));
  }
  return output.toString();
}

var StringMaker = function () {
  this.parts = [];
  this.length = 0;
  this.append = function (s) {
    this.parts.push(s);
    this.length += s.length;
  }
  this.prepend = function (s) {
    this.parts.unshift(s);
    this.length += s.length;
  }
  this.toString = function () {
    return this.parts.join('');
  }
}

//Create attachment for the created email
function CreateEmailAttachment(encodedPdf) {

  //Get order number to name a newly created PDF report
  var orderNumber = Xrm.Page.getAttribute("ordernumber");
  var emailEntityReference = new Sdk.EntityReference("email", emailId);
  var newFileName = fileName + ".pdf";
  if (orderNumber != null)
    newFileName = fileName + orderNumber.getValue() + ".pdf";

  var activitymimeattachment = new Sdk.Entity("activitymimeattachment");
  activitymimeattachment.addAttribute(new Sdk.String("body", encodedPdf));
  activitymimeattachment.addAttribute(new Sdk.String("subject", "File Attachment"));
  activitymimeattachment.addAttribute(new Sdk.String("objecttypecode", "email"));
  activitymimeattachment.addAttribute(new Sdk.String("filename", newFileName));
  activitymimeattachment.addAttribute(new Sdk.Lookup("objectid", emailEntityReference));
  activitymimeattachment.addAttribute(new Sdk.String("mimetype", "application/pdf"));
  Sdk.Async.create(activitymimeattachment, ActivityMimeAttachmentCallBack, function (error) { alert(error.message); });

}

//ActivityMimeAttachment CallBack function
function ActivityMimeAttachmentCallBack(result) {
  Xrm.Utility.openEntityForm("email", emailId);
}


Note: This functionality is tested with Parameterized Custom Report in CRM Online.


The simplest and quickest way to insert data for Many-to-Many relationship in Dynamics CRM is the Drag and drop listbox.
http://www.inkeysolutions.com/DynamicCRMDragAndDropListBox.html

Saturday, 10 November 2012

Dynamics CRM 2011 – Date Time field in custom SSRS report

While using any Date field in your Report you have to be careful about the user’s time zone. Dynamics CRM 2011 stores the date in UTC format so the developer needs to convert it to the preferred date format of user.

Solution

In Report Properties Reference Section add a reference to Microsoft.Crm.Reporting.RdlHelper assembly. Also add a parameter CRM_UserTimeZoneName and set its default value to GMT Standard Time. Whenever you use the date field on report convert the UTC format of date to the user timezone. Use the expression given below:

=CStr(Format(IIf(IsNothing(Fields!ink_billingperiodfromutc.Value),
                            Nothing,                            CDate(Microsoft.Crm.Reporting.RdlHelper.DateTimeUtility.ConvertUtcToLocalTime
                                  (Fields!ink_billingperiodfromutc.Value,                                    Parameters!CRM_UserTimeZoneName.Value))),"dd MMM yyyy"))

I hope this will be helpful.

Friday, 2 November 2012

Dynamics CRM 2011 - How to set Optionset as datasource in Silverlight Combobox

In this post we will see how we can bind a Silverlight Combobox with values of a field of type CRM Optionset.
In the example the combobox is within a grid. The combobox code in the designer would be as given below:
The Designer :
<sdk:DataGridTemplateColumn Header="Category" Width="95" CellStyle="{StaticResource CRM2011_DataGridCellStyle}">

            <sdk:DataGridTemplateColumn.CellTemplate>

                <DataTemplate>

                    <TextBlock Text="{Binding Category}" />

                </DataTemplate>

            </sdk:DataGridTemplateColumn.CellTemplate>

            <sdk:DataGridTemplateColumn.CellEditingTemplate>

                <DataTemplate>

                    <ComboBox SelectedItem="{Binding Category, Mode=TwoWay}"                                 

                                      DisplayMemberPath="Value"

                                        SelectedValuePath="Key"                                                                       

                                  ItemsSource="{StaticResource CategoryListing}" Height="22" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"/>

                </DataTemplate>

            </sdk:DataGridTemplateColumn.CellEditingTemplate>

        </sdk:DataGridTemplateColumn>

In the above code the Static Resource CategoryListing is of type Dictionary. The Value is set as the DisplayMemberPath property and Key is set in the SelectedValuePath property.
In the example we have taken the ItemsSource as Static Resource .So in the codebehind the static resource should be assigned with values before InitializeComponent() is called.

The Model class :

ExpenseNoteModel is the class bound with the Datagrid.
The property “Category” is set in the SelectedItem property. The selected Item would normally display the value as “[key,value]” format where as we would like to display simply the value as selected item. To do so we have used string functions while setting and getting the Category. We set the key property while Set of Category . So we can use the key property of the model class to set selected value for a field.

public class ExpenseNoteModel : ink_expensenote

    {

        private string selectedCategory;

        private string returnValue;

        public string Category

        {

            get

            {

                if (String.IsNullOrEmpty(selectedCategory) == false)

                {

                    string[] category = selectedCategory.Split(',');

                    if (category.Length > 0)

                    {

 

                        returnValue = category[1].TrimEnd(']');

                    }

                }

                return returnValue;

            }

            set

            {

                selectedCategory = value;

                if (String.IsNullOrEmpty(selectedCategory) == false)

                {

                    string[] category = selectedCategory.Split(',');

                    if (category.Length > 0)

                    {

 

                        key = int.Parse(category[0].TrimStart('['));

                    }

                }

            }

        }

        public int key

        {

            get;

            set;

        }

        public Dictionary<int, string> Categories

        {

            get;

            set;

        }

    }

The codebehind:
The function below gets the Optionset labels and values and set them in a dictionary type object.

Dictionary<int,string> categoryListing=new Dictionary<int,string>();  

  

//Add the below lines in the Initialization method of your class

 

public ExpenseNotePage()

{

    this.Resources.Add("CategoryListing", categoryListing);

    GetOptionSetLabels();

    InitializeComponent();

}

 

 

  /// <summary>   

    /// Get options set labels for specified entity's optionset type attribute   

    /// </summary> 

    /// <param name="entityName"></param>   

    /// <param name="attributeName"></param>   

    private void GetOptionSetLabels()

    {

      try

      {

        OrganizationRequest request = new OrganizationRequest();

        request.RequestName = "RetrieveAttribute";

        request["EntityLogicalName"] = "ink_expensenote";

        request["LogicalName"] = "ink_category";

        request["MetadataId"] = Guid.Empty;

        request["RetrieveAsIfPublished"] = true;

        IOrganizationService service = SilverlightUtility.GetSoapService();

        service.BeginExecute(request, new AsyncCallback(OnGetOptionSetLabelsComplete), service);

      }

      catch (Exception ex)

      {

        throw ex;

      }

    }

 

 

 

 

    /// <summary>  

    /// Retrieve the results  

    /// </summary>  

    /// <param name="result"></param>  

    private void OnGetOptionSetLabelsComplete(IAsyncResult result)

    {

      //Get the original query back from the result.  

      OrganizationResponse response = ((IOrganizationService)result.AsyncState).EndExecute(result);

 

      if (response != null && response.Results.Count > 0)

      {

        //Get the actual optionset meta data  

        categories = ((EnumAttributeMetadata)(response.Results[0].Value)).OptionSet;

 

        for (int j = 0; j < categories.Options.Count; j++)

        {

          categoryListing.Add(int.Parse(categories.Options[j].Value.ToString()),categories.Options[j].Label.UserLocalizedLabel.Label.ToString());          

        }       

      }

    }

   

Friday, 26 October 2012

Dynamics CRM 2011 - Propagate the plug-in invalid exception message in JavaScript code.

Recently I came across an issue where I would like to propagate the plug-in InvalidPluginExcecutionException message via JavaScript code. Based on the client requirements I need to trigger a plug-in on click of custom ribbon button on the Opportunity entity. Hence on custom button click I have written a web service call that updates one of custom attributes of an Opportunity entity. So, when system will update this field via client side web service call, the registered plug-in will be triggered automatically.

Usually your InvalidPluginExcecutionException message inside your plug-in code is displayed to user in a standard CRM message box. In my case I am unable to see the same because the plug-in is being triggered via JavaScript web service call. Below is the code snippet that executes my query.

//Asynchronous AJAX function to update a CRM record using OData
  $.ajax({
    type: "POST",
    contentType: "application/json; charset=utf-8",
    datatype: "json",
    data: jsonEntity,
    url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName + "(guid'" + id + "')",
    beforeSend: function (XMLHttpRequest) {
      //Specifying this header ensures that the results will be returned as JSON.             
      XMLHttpRequest.setRequestHeader("Accept", "application/json");
 
      //Specify the HTTP method MERGE to update just the changes you are submitting.             
      XMLHttpRequest.setRequestHeader("X-HTTP-Method", "MERGE");
    },
    success: function (data, textStatus, XmlHttpRequest) {
      //The MERGE does not return any data at all, so we'll add the id 
      //onto the data object so it can be leveraged in a Callback. When data 
      //is used in the callback function, the field will be named generically, "id"
      data = new Object();
      data.id = id;
      if (successCallback) {
        successCallback(data, textStatus, XmlHttpRequest);
      }
    },
    error: function (XmlHttpRequest, textStatus, errorThrown) {
      if (errorCallback) {
 
        errorCallback(XmlHttpRequest, textStatus, errorThrown);
      }
      else {
        ErrorHandler(XmlHttpRequest, textStatus, errorThrown);
      }
    }
  }); 

I have validated all the 3 objects i.e. XmlHttpRequest, textStatus and errorThrown inside errorCallback method to seek the plug-in error message with no success. However I can see the same error message via fiddler!!

Finally, I found a way to parse the response text of xmlHttpRequest and get the exact error message. Below is the code that works for me to alert the plug-in message from client side code.



function ErrorHandler(xmlHttpRequest, textStatus, errorThrown) {
 
  alert(JSON.parse(xmlHttpRequest.responseText).error.message.value);
 
}

I hope this will be helpful.

Saturday, 13 October 2012

Dynamics CRM 2011 - Role Updater

Role Updater makes it easier for administrator and developers to add/ remove privileges to multiple roles at a single time.

Download this tool with the help of below link

http://roleupdater.codeplex.com/

Role Updater is available as an executable. Run the exe and a window is displayed as viewed in screenshot below

clip_image002

You can add a new Connection or select an existing connection. After selecting the connection press the orange button as highlighted in below screenshot and you will be asked for your credentials

clip_image004

If you still find the loading message click on the highlighted button once again. You will see a window as displayed in the screenshot below. Select the roles for which you want to change privileges

clip_image006

Add/Remove privileges from the window that is displayed on selecting role and clicking next.

clip_image008

On clicking next the roles are updated and a window is displayed as viewed in screenshot below.

image

Friday, 5 October 2012

Dynamics CRM 2011 - View Layout Replicator

 

As the name suggests View Layout Replicator is useful for replicating same view layout in other views of same entity.

You can download the View layout replicator from

http://viewlayoutreplicator.codeplex.com/

clip_image002

Run the View Replicator executable file and a window is displayed as viewed above .Select Load Entities as highlighted in image above you will get a window to select connection as viewed above. You can even add a new connection from this window.

Select an entity from the list and the views of the entity are loaded as Source Views and Target Views.

clip_image004

Select the view which you want to change as ‘Target View’ and select the view to which you want to replicate as ‘Source View’.

clip_image006

After selecting Source and target views select the Save Views option as highlighted above. A message is displayed as above. Select the ‘Publish Entity’ option which is next to the highlighted option. On publishing the entity the changes are reflected in the view.

Saturday, 29 September 2012

Packt Publishing reaches 1000 IT titles and celebrates with an open invitation


Birmingham-based IT publisher Packt Publishing is about to publish its 1000th title. Packt books are renowned among developers for being uniquely practical and focused, but you’d be forgiven for not yet being in the know – Packt books cover highly specific tools and technologies which you might not expect to see a high quality book on.

Packt is certain that in its 1000 titles there is at least one book that everyone in IT will find useful right away, and are inviting anyone to choose and download any one of its eBooks for free over its celebration weekend of 28-30th Sep 2012. Packt is also opening its online library for a week for free to give customers an easy to way to research their choice of free eBook.

Packt supports many of the Open Source projects covered by its books through a project royalty donation, which has contributed over $400,000 to Open Source projects up to now. As part of the celebration Packt is allocating $30,000 to share between projects and authors as part of the weekend giveaway, allocated based on the number of copies of each title downloaded.

Dave Maclean, founder of Packt Publishing:
“At Packt we set out 8 years ago to bring practical, up to date and easy to use technical books to the specialist tools and technologies that had been largely overlooked by IT publishers. Today, I am really proud that with our authors and partners we have been able to make useful books available on over 1000 topics and make our contribution to the development community.”

Friday, 28 September 2012

Dynamics CRM 2011 - User Settings Tool

 

You can download this tool from http://crm2011usersettings.codeplex.com/

CRM2011 User Settings Tool can be used to update the user settings of multiple users from one location. The Administrators can select users for whom they want to change settings like Default Pane, Default Tab, Records Per page, Timezone, calendar, start time, end time, email settings and some miscellaneous settings.

You don't have to depend on individual users to update these settings.

The CRM 2011 User Settings is available as a managed solution.

Once you import the solution Go to SettingsàSystemàUser Settings as viewed in screenshot below.

clip_image002

Click on the text “Silverlight User Settings Tool”. A Silverlight control is opened in a new window as viewed in below screenshot.

clip_image004

You can select the users for whom you want to change the settings. Change the settings and click save.

Friday, 21 September 2012

Dynamics CRM 2011 - Dynamics XRM Tools

 

Today, I would like to describe Dynamics XRM Tools.

You can download the Dynamics XRM Tools from http://dynamicsxrmtools.codeplex.com/

Dynamic XRM Tools is available as a managed solution. You just have to import solution and start using it. The toolset consists of a Silverlight application framework that provides a central location for accessing the tools which includes the following:-

  • Trace Tool (on premise only)
  • Statistics
  • OData Query Designer
  • Metadata Browser
  • JavaScript Converter (CRM 4 to CRM 2011)

After importing the solution Go Toà SettingsàDynamics XRM Tools àStart

clip_image002

The Trace Tool is available for On Premise only. This helps you to view the server errors. Two different types of solutions are available for download, CRM Online and CRM On-Premise.

Moving to the Statistics tab as the name suggests it provides record count of total entities and records count per entity. You can even download the generated statistics in excel format. The statistics tab can be viewed as under.

clip_image004

The OData Query Designer can help you to generate an oData query if you are not familiar with oData query syntax and structure.

clip_image006

Select the EntitySet, add required filter criteria, select attribute that should be returned by the query and you can even specify the order by criteria. Click on Generate to generate the query based on your selections. You can click execute to view the results of the query. Check the “Results (ATOM) and Results (JSON)” tabs to view the respective results.

The JavaScript Converter can be used to convert java script from CRM 4 to CRM 2011.

The metadata browser can be used for getting entity and attributes metadata and you can even export the list.

clip_image008

clip_image010

Hope this will be helpful.

Friday, 14 September 2012

Comparing Ribbon Workbench and Visual Ribbon editor

 

You can download Ribbon Workbench from

http://www.develop1.net/public/page/Ribbon-Workbench-for-Dynamics-CRM-2011.aspx

You can download Visual Ribbon Editor from

http://crmvisualribbonedit.codeplex.com/

1) Visual Ribbon Editor is available as executable file whereas Ribbon Workbench is a managed solution.

2) In Visual Ribbon editor you cannot customize system buttons whereas in Ribbon Workbench you can.

3) In Visual Ribbon editor you have a simple button whereas in Ribbon workbench you can add split button, flyout and different options are available. The Visual Ribbon Editor Tool allowed the simple addition of buttons and groups to existing tabs, but any more complex scenarios such as drop down menus, changing the ‘out of the box’ ribbons or adding new tabs was confined to the realms of editing page upon page of hard to understand xml which is now possible with Ribbon workbench.

4) In Ribbon workbench you have to specify a solution whereas in visual ribbon editor you only specify the organization.

5) Visual ribbon editor seems to be faster in updating the changes.

Please feel free to update this blog with your experiences

Friday, 31 August 2012

Dynamics CRM 2011 – Change execution time of Recurring System Jobs

Recently, I needed to change the time for asynchronous Goal Roll-up job. Dynamics CRM allows us to adjust the frequency in hours for this job via System Settings – “Goals” tab. Over here we are having two options, roll-up expiration time in days & roll-up recurrence frequency in hours (by default 24 hours).

image

What I wanted to do is to change the time for Goal roll-up execution, say configure the execution time to mid night or in off hours. Now, the question from where can I validate the current execution time?

You can validate the execution time of all recurring system jobs from Settings tab – System – System Jobs

image

Change the view to Recurring System Jobs, as highlighted in below screenshot

image

Here, in above scenario Goal Roll-Up system job is executing everyday on 12:30 PM. Back to my concern, I would like to change this time to mid night or to off hours. So, how to change the time?

Solution

You can change the execution time for Goal Roll up System job by updating its entry directly from SQL which is an unsupported way.

To implement this first of all find out the AsyncOperationId of the job you want to update.

SELECT [MessageName]      
      ,[OperationType]
      ,[RecurrencePattern]
      ,[Name]
      ,[PostponeUntil]      
      ,[RecurrenceStartTime]
      ,[StatusCode]
      ,[AsyncOperationId]
      ,[CorrelationUpdatedTime]
  FROM [Your_ORG_Name_MSCRM].[dbo].[AsyncOperationBase]
  WHERE OperationType=40 and StatusCode=10

In our case the operation type is 40 for Goal Roll Up. To get required Operation Types and Status code you can refer below MSDN link.

http://msdn.microsoft.com/en-us/library/gg309649.aspx

Get the AsyncOperationId and execute the below update query



Update [Your_ORG_Name_MSCRM].[dbo].[AsyncOperationBase] set
RecurrenceStartTime = '2011-12-09 00:00:00.000',
postponeuntil = '2013-02-02 00:00:00.000'
WHERE AsyncOperationid = '4D1D25D5-8A71-4E31-BAB5-D1866147E5DB'

Note : In above queries replace “Your_ORG_Name_MSCRM” with your database name. 


In above query “Postponeuntil” is the date time field which indicates when the next this job will run. It is in UTC format. So suppose, for GMT + 5:30 time zone (India time zone) if I want to schedule Goa Roll Up job then the value of this field should be set as specified above i.e." 2013-02-02 00:00:00.000”

“RecurrenceStartTime” field which will be used to set next runtime of job. Here the date part is not important as long as it is set in the past.

In below screenshot you can verify that I have successfully updated the roll up time to 5:30 AM.

image