Tuesday, March 26, 2013

CRM 2011: Read contact id from Email From field C#

I used this method to Get a contact id from email "From" field. This method can be customized and you can get any entity you need from this field.


 public Guid? GetContactIdInFromField(IEnumerable<ActivityParty> party)
        {
            var fromItems = party.Select(c => c.ToEntity<ActivityParty>()).ToArray();

            var fromContacts = from c in fromItems
                               where c.PartyId.LogicalName == Contact.EntityLogicalName
                               select c;
            var contactRef = fromContacts.FirstOrDefault();

            if (contactRef == null)
                return null;

            return contactRef.PartyId.Id;
        }

Call function:
var contactFromId = GetContactIdInFromField(emailEntity.From);

Hope this helps.

CRM 2011: Send Email from javascript

I had to add a new button on email form that when clicked will set check a custom checkbox on email form and send the email. I have some extra checks based on email status.

The function that I use looks like this:

function SendEmail() {
 
    var formType = Xrm.Page.ui.getFormType();
    var emailStatus = Xrm.Page.getAttribute("statecode").getValue();
    var emailDirection = Xrm.Page.getAttribute("directioncode").getValue();

    //Update mode && Status= Open (Draft or failed)
    if (formType == 1 || (formType == 2 && emailStatus == "Open")) {

        //outgoing
        if (emailDirection == "1") {
            // Mark the "Is Completed" field in the email
            var completed = Xrm.Page.getAttribute("new_iscompleted");

            if (completed != null) {
                completed.setValue(true);
                if (typeof send == 'function') {
                    //send email
                    send();
                }
            }
        }
        else {
            alert('Action allowed only for "Outgoing" emails');
        }
    }
    else {
        alert("Action not supported for this email status");
    }
}

CRM 2011 Set focus on email body javascript

I had an request that after email form is loaded I needed to set the focus on body field and not on Subject field like crm is doing.
Note that this is an unsupported customization so it might not work for you. You'll need jquery to be included (I used jquery-1.8.3.min).


function SetFocusOnMailBody() {
    var ifrm = document.getElementById("descriptionIFrame");
    ifrm.focus();

    var contentbody = $(ifrm).contents().find("body");
    var char = 0, sel; // character at which to place caret
    contentbody.focus();
    if (document.selection) {
        sel = document.selection.createRange();
        sel.moveStart('character', char);
        sel.select();
    }
}

I called this method after I was setting some fields in Email form at Onload.
The only way I could make it work was to put a timeout (because I could't figure out from where the focus is automatically set on subject field).


setTimeout(function () {
                //set focus on mail body
                SetFocusOnMailBody();
            }, 100);

Hope this helps.

CRM 2011 Show/Hide sections based on a specific optionset value - javascript

My request was that based on a optionset value I had to show only a specific section from a tab and hide the rest. Each optionset value had a specific section and the section label started with this optionset value. So my condition to show the section was - section name starts with "optionset value".


function ShowHideSectionsBySubject() {

    var tabName = "tab_Name";

    var sectionPicklistValue = Xrm.Page.data.entity.attributes.get("optionset_field").getValue();
 
    var sections = Xrm.Page.ui.tabs.get(tabName).sections.get();
    $(sections).each(function (index, section) {
       //hide section
        section.setVisible(false);
        if (sectionPicklistValue != null) {
            if (section.getLabel().startsWith(sectionPicklistValue.toString())) {
                section.setVisible(true);
            }
        }
    });
}

CRM 2011 Dependent optionsets - javascript

The idea is to filter optionset2 values based on selected value from optionset1. In my request I had a specific condition for filter but I'm sure you can use the same idea in your exact scenario.


function FilterOptionset2ByOptionset1() {

    /* Get references to the related fields*/
    var ParentField = Xrm.Page.data.entity.attributes.get("new_case_mainsubject");
    var ChildField = Xrm.Page.data.entity.attributes.get("new_case_subsubjects");

    /* Capture the current value of the child field*/
    var CurrentChildFieldValue = ChildField.getValue();

    var parentValue = ParentField.getValue();
    /* Find the Options that corresponds to the value of the parent field. */
    if (parentValue != null) {
        var controls = ChildField.controls.get();

        var bCurrentValueIsValid = false;

        /*Enable the field and set the options*/
        for (var ctrl in controls) {
            controls[ctrl].setDisabled(false);
            controls[ctrl].clearOptions();

            var existingOptions = controls[ctrl].getAttribute().getOptions();

            for (eo = 0; eo < existingOptions.length; eo++) {
                //The condition for showing optionset2 value based on optionset1 value. The condition that I set bellow is just for test, you need to change it based on your needs.
                if (parseInt(existingOptions[eo].value) == parseInt(parentValue)) {
                    controls[ctrl].addOption(existingOptions[eo]);

                    //if the current child selected value is in the filtered option list
                    if (CurrentChildFieldValue == existingOptions[eo].value) {
                        bCurrentValueIsValid = true;
                    }
                }
            }
        }

        /* If the value is valid, set it. If not, set the child field to null */
        if (bCurrentValueIsValid) {
            ChildField.setValue(CurrentChildFieldValue);
        }
        else {
            ChildField.setValue(null);
        }

        ChildField.setSubmitMode("always");
        ChildField.fireOnChange();

    }
    else {
        //don't do any filter
        var controls = ChildField.controls.get();
        for (var ctrl in controls) {
            controls[ctrl].setDisabled(false);
            controls[ctrl].clearOptions();

            var existingOptions = controls[ctrl].getAttribute().getOptions();

            for (eo = 0; eo < existingOptions.length; eo++) {
                if (existingOptions[eo].value != "null") {
                    controls[ctrl].addOption(existingOptions[eo]);
                }
            }

        }
    }

}


Clear all checkboxes from a specific Tab in javascript - CRM 2011

I had an request that when an option field is changed to a specific value I had to clear all checkboxes found in a specific Tab. So I did this function:


function clearTabCheckboxes(tabName) {
   
    //get tab
    var tab = Xrm.Page.ui.tabs.get(tabName);
   
    tab.sections.forEach(function (section, sectionIndex) {
        section.controls.forEach(function (control, controlIndex) {

            switch (control.getAttribute().getAttributeType()) {
                case "boolean":
                    //for checkbox control, uncheck it
                    control.getAttribute().setValue(false);
                    break;
            }
        });
    });
}

Hope this helps somebody else.

CRM 2011: Populate email From field with a specific queue in javascript

I had to automatically set a specific queue in From field of an email when the form loads. So I created a function that I call it an Onload of email form for this.  Note that I had extra checks (like email to be outgoing).

You need jquery and json2 scripts to be included on this form.
The code for GetServerUrl function you can find it other post of mine (or you can use your own method).

function PopulateFromAddressOnLoad() {

    var formType = Xrm.Page.ui.getFormType();
    var emailStatus = Xrm.Page.getAttribute("statecode").getValue();
    var emailDirection = Xrm.Page.getAttribute("directioncode").getValue();
 
    var defaultQueueEmail = "somequeueemails@email.com";

    if (formType == 1 || (formType == 2 && emailStatus == "Open")) {

        //check if it's outgoing
        if (emailDirection == "1") {

            $.ajax({
                type: "GET",
                async: false,
                contentType: "application/json; charset=utf-8",
                datatype: "json",
                url: GetServerUrl() + "/xrmservices/2011/OrganizationData.svc/QueueSet?$select=Name,QueueId&$filter=EMailAddress eq '" + defaultQueueEmail + "'",
                beforeSend: function (XMLHttpRequest) { XMLHttpRequest.setRequestHeader("Accept", "application/json"); },
                success: function (data, textStatus, XmlHttpRequest) {

                    if (data != undefined && data.d != undefined && data.d.results[0] != undefined) {

                        var queue = data.d.results[0];

                        if (queue != null) {
                            var queueId = queue.QueueId;
                            var lookup = new Array();
                            var lookupItem = new Object();

                            lookupItem.id = queueId;
                            lookupItem.name = queue.Name;
                            lookupItem.typename = "queue";

                            lookup[0] = lookupItem;

                            Xrm.Page.getAttribute("from").setValue(lookup);

                        }
                    }
                },
                error: function (XmlHttpRequest, textStatus, errorThrown) { alert('OData Select Failed '); }
            });
        }
    }
}


CRM 2011 Get the right server url in javascript

I used the method found on Daniel Cai's Blog and it worked for me, hopefully it will for for others too.

My function is a little modified (I removed some checks) but uses the same idea from Daniel's blog. Also the idea with prependOrgName that Andrii Butenko suggested worked for me.

My function looks like this:


function GetServerUrl () {

    var context = Xrm.Page.context;

    if (context.isOutlookClient() && !context.isOutlookOnline()) {
        crmServerUrl = window.location.protocol + "//" + window.location.host;
    } else {
        crmServerUrl = context.getServerUrl();
        crmServerUrl = crmServerUrl.replace(/^(http|https):\/\/([_a-zA-Z0-9\-\.]+)(:([0-9]{1,5}))?/, window.location.protocol + "//" + window.location.host);
        crmServerUrl = crmServerUrl.replace(/\/$/, ""); // remove trailing slash if any
    }
    return crmServerUrl;
}

Update: With the Rollup 12 we can use getClientUrl that will solve all our problems. See bellow description taken from msdn


getClientUrl

Returns the base URL that was used to access the application.
This method is new in Microsoft Dynamics CRM 2011 Update Rollup 12 and the Microsoft Dynamics CRM December 2012 Service Update.
The values returned will resemble those listed in the following table.

 

ClientValue
Microsoft Dynamics CRM (on-premises)
http(s)://server/org
Microsoft Dynamics CRM Online
https://org.crm.dynamics.com
Microsoft Dynamics CRM for Outlook with Offline Access when offline
http://localhost:2525
Return Value
Type: String

Plugin Utils Interface CRM 2011 in C#

For my plugins I usually use this "utils".

I have an Plugin Utils folder where I add these 3 classes:

EntityPlugin.cs

namespace Plugins
{
    public abstract class EntityPlugin<T> where T : Entity
    {
        private static bool LogInit = false;

        public void Execute(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            var utils = new PluginUtils(serviceProvider);

            var entity = utils.PluginContext.InputParameters["Target"] as Entity;

            if (entity == null)
            {
                //if Post Delete dont take entity entityReference
                if (utils.PluginContext.MessageName.ToLower() != "delete" || utils.PluginContext.Stage != 40)
                {
                    var entityReference = utils.PluginContext.InputParameters["Target"] as EntityReference;
                    entity = utils.Service.Retrieve(entityReference.LogicalName, entityReference.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet(true));

                    T target = entity.ToEntity<T>();
                    Execute(utils, target);
                }
                //in case of Post Delete
                else
                {
                    T target = null;
                    Execute(utils, target);
                }            
            }
            else
            {
                T target = entity.ToEntity<T>();
                Execute(utils, target);
            }
        }

        protected abstract void Execute(IPluginUtils utils, T target);

    }
}

IPluginUtils.cs

namespace Plugins.Interfaces
{
    public interface IPluginUtils
    {
        CrmDataContext CrmDataContext { get; }
        IPluginExecutionContext PluginContext { get; }
        IOrganizationService Service { get; }
    }
}

PluginUtils .cs

namespace Plugins
{
    public class PluginUtils : IPluginUtils
    {
        public PluginUtils(IServiceProvider serviceProvider)
        {
            if (serviceProvider == null)
            {
                throw new ArgumentNullException("serviceProvider");
            }

            PluginContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
         
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            Service = serviceFactory.CreateOrganizationService(PluginContext.UserId);
            CrmDataContext = new CrmDataContext(Service);
        }

        public IPluginExecutionContext PluginContext { get; private set; }
        public IOrganizationService Service { get; private set; }
        public CrmDataContext CrmDataContext { get; private set; }
    }
}

In my plugins the code will look something like this:

namespace Plugins.Account
{
    public class PostCreate_AccountDoSomething : EntityPlugin<EntityMappings.Account>, IPlugin
    {
        protected override void Execute(Interfaces.IPluginUtils utils, EntityMappings.Account target)
        {
         
          //do code
          utils.Service.Execute(somerequest);
        }
    }
}



CRM 2011: Associate/Disassociate entities from a relation C#

In my exact requirement I had a N:N relation between 2 entities and I had to associate/disassociate entities that are connected with this N:N relation.
Here are two methods for this.


 public static void DisassociateEntitiesToTarget(EntityReference target, EntityReferenceCollection relatedEntities, string relationName, IOrganizationService service)
        {

            // Add the relationship schema name
            Relationship relationship = new Relationship(relationName);

            // Disassociate the entities records to target
            service.Disassociate(target.LogicalName, target.Id, relationship, relatedEntities);

        }

Call the method
DisassociateEntitiesToTarget(targetEntity.ToEntityReference(), relatedEntities, "relationName", utils.Service);

        public static void AssociateEntitiesToTarget(EntityReference target, EntityReferenceCollection relatedEntities, string relationName, IOrganizationService service)
        {

            // Add the relationship schema name
            Relationship relationship = new Relationship(relationName);
         
            // Associate the entities to target
            service.Associate(target.LogicalName, target.Id, relationship, relatedEntities);
         
        }

Call the method:
AssociateEntitiesToTarget(targetEntity.ToEntityReference(), entitiesToAssociate, "relationName", utils.Service);

Get related entities from Many to many relation CRM 2011

I had a request to obtain all related entities from N:N relation for a specific entity in this relation. There might be other ways to achieve this but this method I used and it worked for me, so I thought to share it with you in case somebody else will need it.

This is the function that returns the a collection of entities for a specific entity from this relation.


 /// <summary>
        /// get entities from many to many relation
        /// </summary>
        /// <param name="entityToRetrieve">the entity name that we want to retrieve</param>
        /// <param name="relationName">relation name</param>
        /// <param name="targetEntity">entity name</param>
        /// <param name="service"></param>
        /// <returns>collection of entities</returns>
        public static DataCollection<Entity> GetRelatedEntitDataFromManyToManyRelation(string entityToRetrieve, string[] columnsToRetieve, string relationName, EntityReference targetEntity, IOrganizationService service)
        {
            DataCollection<Entity> result = null;
         
                QueryExpression query = new QueryExpression();
                query.EntityName = entityToRetrieve;
                query.ColumnSet = new ColumnSet(columnsToRetieve);
                Relationship relationship = new Relationship();

                relationship.SchemaName = relationName;

                RelationshipQueryCollection relatedEntity = new RelationshipQueryCollection();
                relatedEntity.Add(relationship, query);
                RetrieveRequest request = new RetrieveRequest();
                request.RelatedEntitiesQuery = relatedEntity;
                request.ColumnSet = new ColumnSet(targetEntity.LogicalName + "id");
                request.Target = targetEntity;
                RetrieveResponse response = (RetrieveResponse)service.Execute(request);


                if (((DataCollection<Relationship, EntityCollection>)(((RelatedEntityCollection)(response.Entity.RelatedEntities)))).Contains(new Relationship(relationName)) && ((DataCollection<Relationship, EntityCollection>)(((RelatedEntityCollection)(response.Entity.RelatedEntities))))[new Relationship(relationName)].Entities.Count > 0)
                {
                    result = ((DataCollection<Relationship, EntityCollection>)(((RelatedEntityCollection)(response.Entity.RelatedEntities))))[new Relationship(relationName)].Entities;
                }
         
            return result;
        }


You can call this function is like this:
var relatedAccountsForTarget = GetRelatedEntitDataFromManyToManyRelation("account", new string[]{ "accountid" }, "Type here relationName", targetEntity.ToEntityReference(), utils.Service);

Retrieve option set text in CRM 2011 server side

This method was taken from Guru Prasad's Blog. Here we can find several methods based on your needs that you can use to achieve the needed result. Thank you Guru!

I'll share one of the methods that I used in my code using metadata service:

public static string GetoptionsetText(string entityName, string attributeName, int optionSetValue, IOrganizationService service)

        {
            string AttributeName = attributeName;
            string EntityLogicalName = entityName;
            RetrieveEntityRequest retrieveDetails = new RetrieveEntityRequest
            {
                EntityFilters = EntityFilters.Attributes,
                LogicalName = EntityLogicalName
            };
            RetrieveEntityResponse retrieveEntityResponseObj = (RetrieveEntityResponse)service.Execute(retrieveDetails);
            Microsoft.Xrm.Sdk.Metadata.EntityMetadata metadata = retrieveEntityResponseObj.EntityMetadata;
            Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata picklistMetadata = metadata.Attributes.FirstOrDefault(attribute => String.Equals
            (attribute.LogicalName, attributeName, StringComparison.OrdinalIgnoreCase)) as Microsoft.Xrm.Sdk.Metadata.PicklistAttributeMetadata;
            Microsoft.Xrm.Sdk.Metadata.OptionSetMetadata options = picklistMetadata.OptionSet;
            IList<OptionMetadata> OptionsList = (from o in options.Options
                                                 where o.Value.Value == optionSetValue
                                                 select o).ToList();
            string optionsetLabel = (OptionsList.First()).Label.UserLocalizedLabel.Label;
            return optionsetLabel;
        }