Tuesday, April 28, 2015

Run report from custom ribbon button for selected records

MS CRM has feature to run report on selected records, when you create report using SQL queries you need to specify one report parameter with prefix CRMAF_, this parameter will allow you to pre- filter report.
And when user selects records from grid and run report from report menu, then CRM asking to select records / use these records dialog, in this dialog user need to select either all applicable records, all records on all pages in the current view or selected record.
But sometime user doesn't want to see this dialog or wants custom button to run specific report on selected records.
To do this, first need to add custom button on ribbon and add call JavaScript function on button click.
When calling JavaScript function from ribbon pass Crmparamter SelectedControlSelectedItemIds
 as parameter to JavaScript function, so that we will get all selected record ids in JavaScript function.

And JavaScript function should be like

function RunReportforSelectedRecords(selectedRecords)
{
    var selectedIds;
    for (var i = 0; i < selectedRecords.length; i++) {
        if (i == 0)
            selectedIds = selectedRecords[i];
        else
            selectedIds = selectedIds + "," + selectedRecords[i];
    }
     var rdlName = "Your Report Name.rdl";
    var reportGuid = "8ca0d6b4-f8ec-e411-8ca2-0050568c6d7d"// Report GUID - Replace with your report GUID
    var entityType = "10012"// Entity Type code - Replace
    var para = encodeURIComponent(entityGuid);
    var url = Xrm.Page.context.getClientUrl() + "/crmreports/viewer/viewer.aspx?action=filter&helpID=" + rdlName + "&id={" + reportGuid + "}&p:selectedContactIds=" + selectedIds;
    window.open(url, null, 800, 600, truefalsenull);
}

This will open new window and report will be executed.

To open report I used report URL

"/crmreports/viewer/viewer.aspx?action=filter&helpID=" + rdlName + "&id={" + reportGuid + "}&p:selectedContactIds =" + selectedIds


This URL contains

action:
Two possible values for this parameter are run or filter. When run is used, the report will be displayed using the default filters. When filter is used, the report will display a filter that the user can edit before choosing the Run Report button to view the report.
helpID:
This parameter is optional. For reports that are included with Microsoft Dynamics CRM the value in this parameter allows the Help button to display appropriate content about this report when Help on This Page is chosen. The value should correspond to the report FileName attribute value.
Id:
This parameter is the report ReportId attribute value.

More details on Opening a Report by using a URL



p: CustomParameterName
This is custom parameter I used in SSRS report.
To pass parameter value using url we need to specify p:{parameter name}

In this example I am getting string of selected record GUIDs and I am passing it to report.
And I am using these selected GUID in report query like below



CREATE TABLE #selectedContacts(ContactId uniqueidentifier)

 declare @delimiter CHAR(1) =','
  DECLARE @start INT, @end INT
    SELECT @start = 1, @end = CHARINDEX(@delimiter, @selectedContactIds)
    WHILE @start < LEN(@selectedContactIds) + 1 BEGIN
        IF @end = 0 
            SET @end = LEN(@selectedContactIds) + 1
              INSERT INTO #selectedContacts (ContactId) 
        VALUES(SUBSTRING(@selectedContactIds, @start, @end - @start))
        SET @start = @end + 1
        SET @end = CHARINDEX(@delimiter, @selectedContactIds, @start)
    END 

select FirstName, LastName
         , EMailAddress1
         , Telephone1
 from Contact
where ContactId in
(
  select contactid from #selectedContacts
)


When use this query as it is in report SSRS will create report parameter with name @selectedContactIds as this is the only variable not declared in this query.

 In this approach passing record ids in URL, generally URL will support up to 2048 characters, and that’s limitation of around 50 records will come when executing report this way. 

Change Customer Lookup Behaviour

In MS CRM there are some lookups which allows multiple entities, like Customer lookup. 
When clicked on customer lookup, we have choice to select either account or contact.





But some time requirements are allow either account or contact only for customer lookup or default customer lookup to contact instead of account.
Right now there is not any supported way to achieve this, but with unsupported way you can easily achieve these requirements.

Note: Below code is unsupported code for MS CRM. JavaScript code is using DOM.

Add following JavaScript code on form load.

1.     Customer lookup default to Contact.


function CustomerLookupDefaultToContact() {
    var customerCtrl = Xrm.Page.getControl("customerid");
    customerCtrl.setFocus();

    var customerInput = document.getElementById("customerid_i");
    customerInput.setAttribute("lookuptypes", "2,1");   //2: Contact , 1: Account
    customerInput.setAttribute("defaulttype", 2);       // Set defaultType to Contact
    customerInput.setAttribute("autoresolve", 2);       // Partially entered name will be resolved with contact record.
    customerInput.setAttribute("createpermissiondictionary", "account:true,contact:true");
    customerInput.setAttribute("lookuptypenames", "account:1:Account,contact:2:Contact");
    customerInput.setAttribute("DefaultViewId", "{A2D479C5-53E3-4C69-ADDD-802327E67A0D}"); // View id to set Default contact view. Replace with your View Id

}





2.     Customer lookup only for Contacts


function CustomerLookupOnlyContact() {
  
    var customerCtrl = Xrm.Page.getControl("customerid");
    customerCtrl.setFocus();

    var customerInput = document.getElementById("customerid_i");
    customerInput.setAttribute("lookuptypes", "2");   //2: Contact , 1: Account
    customerInput.setAttribute("defaulttype", 2);       // Set defaultType to Contact
    customerInput.setAttribute("autoresolve", 2);       // Partially entered name will be resolved with contact record.
    customerInput.setAttribute("createpermissiondictionary", "account:false,contact:true");
    customerInput.setAttribute("lookuptypenames", "contact:2:Contact");
    customerInput.setAttribute("DefaultViewId", "{A2D479C5-53E3-4C69-ADDD-802327E67A0D}"); // View id to set Default contact view. Replace with your View Id

}



3.     Customer lookup only for Account

function CustomerLookupOnlyAccount() {
  
    var customerCtrl = Xrm.Page.getControl("customerid");
    customerCtrl.setFocus();

    var customerInput = document.getElementById("customerid_i");
    customerInput.setAttribute("lookuptypes", "1");   //2: Contact , 1: Account
    customerInput.setAttribute("defaulttype", 1);       // Set defaultType to Contact
    customerInput.setAttribute("autoresolve", 1);       // Partially entered name will be resolved with contact record.
    customerInput.setAttribute("createpermissiondictionary", "account:false,contact:true");
    customerInput.setAttribute("lookuptypenames", "account:1:Account");
    customerInput.setAttribute("DefaultViewId", "{A9AF0AB8-861D-4CFA-92A5-C6281FED7FAB}"); // Default view to show records. Replace with your View Id

}




Monday, April 27, 2015

Hide Ribbon Button based on View selected

Sometimes we need to hide some button based on view selected.
CRM doesn’t have this functionality, and there is not supported way to achieve this. With small unsupported JavaScript code you can easily hide ribbon buttons based on view selected.
To do this, need to add Enable rule to button command.
I am using Ribbon workbench to add Enable Rule.
1.      If want to hide custom button then select button command, and click on Enable rules

If want to hide existing CRM button then need to customize button command, and then add Enable rule.




2.      Add new Enable rule to command




3.      Add Step to Enable rule and select Custom JavaScript Rule


4.      Set properties to javascript rule as


Default : True
FunctionName: HideButtonBasedOnViewSelected
InvertResult: False
Library: select JavaScript library where HideButtonBasedOnViewSelected function code is.
Parameters: Need one parameter to HideButtonBasedOnViewSelected function,

Add Crm parameter, and set parameter value as SelectedControl



5.      Now save and upload changes to CRM, and publish changes.
6.      JavaScript code required to hide button is
for CRM 2013
function HideButtonBasedOnViewSelected (selectedCtrl) {
      
        var view = selectedCtrl.get_$1X_3();
        var query = view.selectedViewName;

        if (query == 'Your View Name') {
            return false;
        }
        else
            return true;
    }
For CRM 2015
function HideButtonBasedOnViewSelected (selectedCtrl) {             
        var query = selectedCtrl.get_viewTitle();
        if (query == 'Your View Name') {
            return false;
        }
        else
            return true;
    }
To get selected view name need to use some unsupported JavaScript. 
"selectedCtrl.get_$1X_3();" or "selectedCtrl.get_viewTitle()"
This is giving all details about selected view and default view of this grid. 
Here I am hiding button for all views except view name is "Active Students - 2015"
For CRM 2013:
function HideButtonBasedOnViewSelected(selectedCtrl) {
        
        var view = selectedCtrl.get_$1X_3();
        var query = view.selectedViewName;

        if (query != 'Active Students - 2015') {
            return false;
        }
        else
            return true;
    }

For CRM 2015:
function HideButtonBasedOnViewSelected(selectedCtrl) {        
           var query = selectedCtrl.get_viewTitle();
        if (query != 'Active Students - 2015') {
            return false;
        }
        else
            return true;
    }

Enroll button is visible only for Active student -2015 view.