Monday 7 May 2012

Ribbon Customization Part 11:Enable,Disable Ribbon button based on Security Role

After  a small gap I am blogging again, as I have there  there is a requirement for the ribbon controls to he shown depending on the security role.
So in this post I am  going to show a  custom button, in the Case homepage grid  under the Actions group. and I will make this button to be enabled only when the user with the “System Admin”role has logged in and I don’t enable this button for the rest of the users. << and also this button has the functionality for the Resolve Case>>
Steps to follow
  1. Create a solution
  2. Add  the entity ‘case’
  3. Add a Javascript webresource with the following code and named as ‘CommonLibrabry’
  4. function UserHasRole(roleName) {

     

        var serverUrl = Xrm.Page.context.getServerUrl();

        var oDataEndpointUrl = serverUrl + "/XRMServices/2011/OrganizationData.svc/";

        oDataEndpointUrl += "RoleSet?$top=1&$filter=Name eq '" + roleName + "'";

        var service = GetRequestObject();

        if (service != null) {

            service.open("GET", oDataEndpointUrl, false);

            service.setRequestHeader("X-Requested-Width", "XMLHttpRequest");

            service.setRequestHeader("Accept", "application/json, text/javascript, */*");

            service.send(null);

            var requestResults = eval('(' + service.responseText + ')').d;

            if (requestResults != null && requestResults.results.length == 1) {

                var role = requestResults.results[0]; 

                var id = role.RoleId;

                var currentUserRoles = Xrm.Page.context.getUserRoles();

                for (var i = 0; i < currentUserRoles.length; i++) {

                    var userRole = currentUserRoles[i];

                    if (GuidsAreEqual(userRole, id)) {

                        return true;

                    }

                }

            }

        }

     

        return false;

    }

     

    function GetRequestObject() {

        if (window.XMLHttpRequest) {

            return new window.XMLHttpRequest;

        }

        else {

            try {

                return new ActiveXObject("MSXML2.XMLHTTP.3.0");

            }

            catch (ex) {

                return null;

            }

        }

    }

    function GuidsAreEqual(guid1, guid2) {

        var isEqual = false;

        if (guid1 == null || guid2 == null) {

            isEqual = false;

        }

        else {

            isEqual = guid1.replace(/[{}]/g, "").toLowerCase() == guid2.replace(/[{}]/g, "").toLowerCase();

        }

     

        return isEqual;

    }

     

    function callMain() {

     

    if(UserHasRole("System Administrator"))

    {

    return true;

    }

    else 

    {

    return false;

    }

     

    }
  5. Export the solution
  6. Unzip the solution
  7. Edit the customization
  8. Add the below custom action to display the button under the –Actions Group in the HomepageGrid
  9. <CustomAction Id ="sample.HomepageGrid.incident.MainTab.Actions.CustomAction" 

    Location ="Mscrm.HomepageGrid.incident.MainTab.Actions.Controls._children" 

                           Sequence ="10">

              <CommandUIDefinition>           

                  <Button Id="sample.HomepageGrid.incident.MainTab.Actions.Button"

                          Command="sample.HomepageGrid.incident.MainTab.Actions.Command"

                          LabelText="$LocLabels:sample.HomepageGrid.incident.MainTab.Actions.LabelText"

                          ToolTipTitle="$LocLabels:sample.HomepageGrid.incident.MainTab.Actions.LabelText"

                          ToolTipDescription="$LocLabels:sample.HomepageGrid.incident.MainTab.Actions.ToolTip"

                          TemplateAlias="o1"

                          Image16by16="/_imgs/ribbon/AddEmail_16.png"

                          Image32by32="/_imgs/ribbon/Email_32.png" />             

              </CommandUIDefinition>         

            </CustomAction>
  10. Define the command definition., basically this button has the functionality of << Resolving a case>>
    1. this will enable when only one record is selected in the Grid and also if the user has the ‘System Administrator” Role
    2. <CommandDefinition Id="sample.HomepageGrid.incident.MainTab.Actions.Command">

                 <EnableRules>

                   <EnableRule Id="Mscrm.CustomcheckRole" />

                   <EnableRule Id="Mscrm.SelectionCountExactlyOne" />             

                   <EnableRule Id="Mscrm.VisualizationPaneNotMaximized" />

                 </EnableRules>

                 <DisplayRules>

                   <DisplayRule Id="Mscrm.CanChangeIncidentForm" />

                 </DisplayRules>

                 <Actions>

                   <JavaScriptFunction FunctionName="Mscrm.IncidentActions.resolveCase" Library="/_static/_common/scripts/ribbonactions.js">

                     <CrmParameter Value="FirstSelectedItemId" />

                     <CrmParameter Value="SelectedControl" />

                   </JavaScriptFunction>

                 </Actions>

               </CommandDefinition>
  11. Provide the appropriate Display rule as well as the Enable rules as shown below
  12. <DisplayRules>

               <DisplayRule Id="Mscrm.CanChangeIncidentForm">

                 <EntityPrivilegeRule EntityName="incident" PrivilegeType="Write" PrivilegeDepth="Basic" />

                 <EntityPrivilegeRule EntityName="incident" PrivilegeType="AppendTo" PrivilegeDepth="Basic" />

                 <EntityPrivilegeRule EntityName="activitypointer" PrivilegeType="Create" PrivilegeDepth="Basic" />

                 <EntityPrivilegeRule EntityName="activitypointer" PrivilegeType="Append" PrivilegeDepth="Basic" />

               </DisplayRule>            

             </DisplayRules>

             <EnableRules>

               <EnableRule Id="Mscrm.SelectionCountExactlyOne">

                 <SelectionCountRule Minimum="1" Maximum="1" AppliesTo="SelectedEntity" />

               </EnableRule>

               <EnableRule Id="Mscrm.VisualizationPaneNotMaximized">

                 <CustomRule FunctionName="Mscrm.RibbonActions.disableButtonsWhenChartMaximized"

             Library="/_static/_common/scripts/RibbonActions.js">

                   <CrmParameter Value="SelectedControl" />

                 </CustomRule>

               </EnableRule>

               <EnableRule Id="Mscrm.CustomcheckRole">

                 <CustomRule FunctionName="callMain"

     Library="$webresource:new_CommonLibrary">

                 </CustomRule>

               </EnableRule>

             </EnableRules>
  13. Provide the locales as shown below
  14. <LocLabels>

             <LocLabel Id="sample.HomepageGrid.incident.MainTab.Actions.LabelText">

               <Titles>

                 <Title languagecode="1033"

                         description="Custom Button1" />

               </Titles>

             </LocLabel>

             <LocLabel Id="sample.HomepageGrid.incident.MainTab.Actions.ToolTip">

               <Titles>

                 <Title languagecode="1033"

                         description="Custom Button1" />

               </Titles>

             </LocLabel>

           </LocLabels>
  15. The screenshot appears as  shown below. when I logged with a user having system Admin role
  16. EnableRibbon button based on securityrole_CRM2011
  17. The screenshot appears as  shown below. when I logged with a user who doesn’t have system Admin role
  18. disable ribbon button based on security Role_CRM 2011
  19. The entire source code can be downloaded from here
  20. Happy learning Smile

Friday 20 April 2012

Sending Email using Email Template in CRM 2011

Hi,
Here is the sample code to send an Email using Email template name.
Before start below are few keywords
  • Template Name   (i.e., Name of the Template)
  • Regarding Id        (i.e., GUID of the entity record which template associated with)
  • Regarding Type   (i.e., Logical name of the entity which template associated with)
  • ActivityParty[]     (i.e., Sender & Receivers Can be Users/Contacts/Accounts/Leads)
  • IOrganizationService crmService
 public void SendEmailUsingTemplate(IOrganizationService crmService,
ActivityParty[] fromParty,  ActivityParty[] toParty,
string templateName,
Guid regardingId, string regardingType)
{
try
{
// Create e-mail message.
var email = new Email
{
To = toParty,
From = fromParty,
DirectionCode = true
};
if (!string.IsNullOrEmpty(templateName))
{
Guid templateId = Guid.Empty;
// Get Template Id by Name
Entity template = GetTemplateByName(crmService, templateName);
if (template != null && template.Id != null)
{
var emailUsingTemplateReq = new SendEmailFromTemplateRequest
{
Target = email.ToEntity<Entity>(),
TemplateId = template.Id,
RegardingId = regardingId,
RegardingType = regardingType
};
var emailUsingTemplateResp = (SendEmailFromTemplateResponse)crmService.Execute(emailUsingTemplateReq);
}
else
{
// “****No email template exists with the given name ****”);
}
}
}
catch (Exception ex)
{
throw;
}
}
     private Entity GetTemplateByName(string title, IOrganizationService crmService)
{
var query = new QueryExpression();
query.EntityName = Template.EntityLogicalName;
var filter = new FilterExpression();
var condition1 = new ConditionExpression(“title”, ConditionOperator.Equal, new object[] { title });
filter.AddCondition(condition1);
query.Criteria = filter;
EntityCollection allTemplates = crmService.RetrieveMultiple(query);
Entity emailTemplate = new Template();
if (allTemplates.Entities.Count > 0)            {
emailTemplate = allTemplates.Entities[0];
}
return emailTemplate;
}
How Do I call this method -
  • Prepare From and To Users/Contacts/Accounts
  • Pass Service,Template Name,Regarding details
// Prepare “From” activity parties
var from = new ActivityParty
{
PartyId = new EntityReference(SystemUser.EntityLogicalName, {GUID of User})
};
var fromParty = new[] { from };
// Prepare “To” activity parties
var to = new ActivityParty
{
PartyId = new EntityReference(SystemUser.EntityLogicalName, {GUID of User})
};
var toParty = new[] { to };
var orgProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, credentials, null);
IOrganizationService orgnaizationService = orgProxy;
Guid regardingntityId={GUID of record} // Ex – Guid of contact
string regardingEntityName = “contact” // Logical name ‘contact’
SendEmailUsingTemplate(orgnaizationService , fromParty, toParty, “templateName”, regardingntityId, regardingEntityName);
Hope it helps :)

Saturday 14 April 2012

Microsoft Dynamics CRM 2011 : How to send Email Notificaiton on Record Sharing?

Solution: Workflows are very useful in Microsoft Dynamics CRM 2011, can be used to send automated email messages, create, update, assign records etc.. but can only be triggered on record creation, status change, assignment, attribute change and deletion and what if it is required to trigger workflow on entity SDK message processing i.e. record sharing etc. For such requirements, i am taking an example of sending email notifications on lead record sharing, You can follow the steps below for sending email notification on lead record sharing.

1.    Create two new attributes in lead entity
    
     a. new_IsSharedRecord (Type = Bit/Two Options)
    
     b. new_LastSharedDateTime (Type = DateTime)

2.    Create plugin that will be triggered on “GrantAccess” message of lead entity and update “new_isSharedRecord”  attribute value to “True” and also store current system date time in “new_LastSharedDateTime”

3.    Create new workflow that will be triggered when “new_isSharedRecord” attribute value will be changed

4.    Check if attribute “new_isSharedRecord” = true then execute below steps

a.    Update attribute value “new_isSharedRecord” = false

b.    Send email message



[Plugin Code]



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;
using Microsoft.Crm.Sdk;

namespace wod.Crm.LeadShareAlert
{
    public class wodPlugin : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the execution context from the service provider.
            Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
                serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

            IOrganizationServiceFactory wod_serviceFactory = null;

            IOrganizationService wod_CrmService = null;

            try
            {
                wod_serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                wod_CrmService = wod_serviceFactory.CreateOrganizationService(context.UserId);

                if (context.InputParameters.Contains("Target")
                && context.InputParameters["Target"] is EntityReference)
                {
                    switch (context.MessageName)
                    {
                        case "GrantAccess":

                            EntityReference wod_PluginEntity = (EntityReference)context.InputParameters["Target"];

                            if (wod_PluginEntity.LogicalName == "lead")
                            {
                                Entity wodLead = new Entity(wod_PluginEntity.LogicalName);

                                wodLead.Attributes.Add("leadid", wod_PluginEntity.Id);
                                wodLead.Attributes.Add("new_issharedrecord", true);
                                wodLead.Attributes.Add("new_lastshareddatetime", DateTime.Now);

                                wod_CrmService.Update(wodLead);
                            }

                            break;
                    }
                }

            }

            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw new InvalidPluginExecutionException(ex.Detail.InnerText);
            }
            catch (Exception ex)
            {
                throw new InvalidPluginExecutionException(ex.Message);
            }
        }
    }
}

Originaly posted on: http://worldofdynamics.blogspot.com/2011/05/scenario-on-record-sharing-sending.html