Saturday, April 6, 2013

Related records count in CRM 2011 chart

        Below is the screenshot of  Cases associated with Contact record(Fig. A). Here we can see two Cases for this Contact. In this exercise, the requirement is to display the related Case count for each Contacts in an Organization using charts.

Fig. A. Cases associated with Contact


Follow the below steps to create this chart in MSCRM2011.
  • Settings à Customizations à Customize the System à Entities à Case à Charts à New.
  • Name the chart à Select Case(Count) in Series and any field in Horizontal à Save & Close.
  • Select newly created chart à More Actions à Export Chart.
  • Open exported chart in Visual Studio.
  • Replace <entity> tag with below XML and Save.
    <entity name="incident">
        <attribute alias="_CRMAutoGen_aggregate_column_Num_0" name="incidentid" aggregate="count" />
       <link-entity name="contact" from="contactid" to="customerid" alias="aa">
            <attribute name="fullname" groupby="true" alias="_CRMAutoGen_groupby_column_Num_0"  />
            <filter type="and">
                <condition attribute="statecode" operator="eq" value="0"/>
            </filter>
        </link-entity>
    </entity>

  • In Charts, More Actions à Import Chart à Browse for updated XML file à OK à Replace à Close.
  • You can add this chart to Dashboard and which will looks like below(Fig. B).
Fig. B. Contact Vs Case count chart in Dashboard.

Friday, March 15, 2013

Dependent Picklist(Dynamic Option Set) in CRM 2011

             MS CRM 2011 doesn't have Out-Of-the-Box functionality to filter the option set values based on the value selected in another option set. We can implement this functionality using Javascript. Lets consider one example here. We have two option set fields called Country and City. City field has to be filtered based on the value selected in Country field. Below JScript code will do this functionality.

Prerequisite:

1. Create two optionset fields named new_country(with values say, India, USA and Srilanka) and new_city(with values say, Bangalore, Delhi, New York, Colombo, California and Hyderabad).
2. Create a JScript Webresource with the below code.
3. Attach this webrecource to call optionSetChanged() method on change of Country field.
4. Configure getCollection() method to match the Cities with respect to Country.


/************************
Functionality: To populate the picklist values based on the value selected in another picklist.
Field Name: new_country
Field Event: OnChange
***************************/

function optionSetChanged() {

    ///<summary>
    /// Change the dependent picklist values based on the value selected in the control picklist.
    ///</summary>

    var _collection = getCollection();
    var _cityOptionset = Xrm.Page.ui.controls.get("new_city");
    var _cityOptions = _cityOptionset.getAttribute().getOptions();
    var _selectedCountry = Xrm.Page.getAttribute("new_country").getText();
        
    // If Country is empty, then clear the City field.
    if (_selectedCountry == "") {
        _cityOptionset.clearOptions();
    }
    else {
        for (var i = 0; i < _collection.length; i++) {
            if (_selectedCountry.toLowerCase() == _collection[i].Country.toLowerCase()) {
                _cityOptionset.clearOptions();
                for (var j = 0; j < _collection[i].Cities.length; j++) {
                    for (var k = 0; k < _cityOptions.length; k++) {
                        if (_collection[i].Cities[j].toLowerCase() == _cityOptions[k].text.toLowerCase()) {
                            _cityOptionset.addOption(_cityOptions[k]);
                            break;
                        }
                    }
                }
                break;
            }
        }
    }
}


function getCollection() {

    ///<summary>
    /// Creates and returns a collection of Cities with respect to their Countries.
    ///</summary>

    var _collection = new Array();
    var India_Cities = new Array("Bangalore", "Delhi", "Hyderabad");
    var India_obj = { Country: "India", Cities: India_Cities };
    _collection.push(India_obj);

    var Srilanka_Cities = new Array("Colombo");
    var SriLanka_obj = { Country: "SriLanka", Cities: Srilanka_Cities };
    _collection.push(SriLanka_obj);

    var USA_Cities = new Array("California", "New York");
    var USA_obj = { Country: "USA", Cities: USA_Cities };
    _collection.push(USA_obj);

    return _collection;
}



    This functionality can be tested by changing the Country field and check the values populated in City field. Result of this dependent pick list is can be seen here.

Country: India and Cities: Bangalore,Delhi & Hyderabad.

Country: USA and Cities: California & NewYork.

Friday, December 21, 2012

Hide 'Add New' button from ribbon

   Sometimes we need to remove Add New or Add Existing button from ribbon. In below image we can see the 1:N relationship between Order and Invoice. To remove Add New button from Invoice entity in Order record, we need to export Invoice entity.
Add New button in 1:N relation between Order and Invoice.


  • Open customizations.xml from exported solution.
  • Open invoiceribbon.xml from SDK(\SDK\samplecode\cs\client\ribbon\exportribbonxml\exportedribbonxml) and select <CommandDefinition> with Id="Mscrm.AddNewRecordFromSubGridStandard".
  • Paste the copied <CommandDefinition> inside <CommandDefinitions> in customizations.xml.
  • Insert new <DisplayRuleinside <DisplayRulesto hide Add New button(can be seen in below tags with Id="Mscrm.HideAddNewForOrder").

<CommandDefinition Id="Mscrm.AddNewRecordFromSubGridStandard">
    <EnableRules>
        <EnableRule Id="Mscrm.AppendToPrimary" />
        <EnableRule Id="Mscrm.EntityFormIsEnabled/>
    </EnableRules>

    <DisplayRules>
        <DisplayRule Id="Mscrm.ShowForOneToManyGrids/>
        <DisplayRule Id="Mscrm.AppendToPrimary/>
        <DisplayRule Id="Mscrm.CreateSelectedEntityPermission/>
        <DisplayRule Id="Mscrm.AppendSelected/>
        <DisplayRule Id="Mscrm.HideAddNewForChildEntities/>
        <DisplayRule Id="Mscrm.HideAddNewForOrder/>
    </DisplayRules>
    <Actions>
  <JavaScriptFunction FunctionName="Mscrm.GridRibbonActions.addNewFromSubGridStandardLibrary="/_static/_common/scripts/RibbonActions.js">
            <CrmParameter Value="SelectedEntityTypeCode/>
            <CrmParameter Value="PrimaryEntityTypeCode/>
            <CrmParameter Value="FirstPrimaryItemId/>
            <CrmParameter Value="PrimaryControl/>
        </JavaScriptFunction>
    </Actions>

</CommandDefinition>

  • Define <DisplayRuleunder <DisplayRulesin <RuleDefinitionsas below.
<DisplayRule  Id="Mscrm.HideAddNewForOrder">
    <FormEntityContextRule EntityName="salesorderDefault="true" InvertResult="true" />
</DisplayRule>

  • This <DisplayRulewill hide Add New button ONLY from Invoice which is related with Order.

Thursday, December 20, 2012

Add a ribbon button in CRM 2011


   The followings are the steps to be followed to add a ribbon button in CRM 2011.
1.Create a solution in CRM 2011.
2.Add button to an entity ribbon.

1.Create a solution in CRM 2011

  • Create new solution in CRM 2011(Settings à Customization à Solution à New)
  • Open created solution and add desired entity(Account in this example) and avoid adding related components. Save and close the solution.
  •   Select the solution and export it as Unmanaged.
  • Extract the zip file and open customizations.xml in Visual Studio.


2.Add button to an entity ribbon

  • In opened customizations.xml file, search for <Ribbondiff> tag.You can see the below block of tags if there is no ribbon customization for this entity.
   <RibbonDiffXml>
     <CustomActions />
     <Templates>
        <RibbonTemplates Id="Mscrm.Templates">
        </RibbonTemplates>
     </Templates>
     <CommandDefinitions />
     <RuleDefinitions>
        <TabDisplayRules />
        <DisplayRules />
        <EnableRules />
     </RuleDefinitions>
     <LocLabels />
  </RibbonDiffXml>


  • In this example, we are adding a 'Close' button to an Account record ribbon to close the form.
  • We must have created 16X16 and 32X 32 Image webresources for Close button.
  • Replace <CustomActions /> tag with below XML tags.
    <CustomActions>
     <CustomAction Id="Account.CustomAction.Close" Location="Mscrm.Form.account.MainTab.ExportData.Controls._children">
        <CommandUIDefinition>
           <Button Id="Account.form.Button.CloseCommand="Account.form.Button.Close.CommandSequence="34 LabelText="Close ToolTipTitle="Close ToolTipDescription="Close the form.TemplateAlias="o1" Image16by16="$webresource:new_/Images/CloseButton16X16.png" Image32by32="$webresource:new_/Images/CloseButton32X32.png" />
        </CommandUIDefinition>
     </CustomAction>
  </CustomActions>


  • Now we have to add command definition for Close button. CommandDefinition tag contains DisplayRules,  EnableRules and Actions for the button. Actions describes the action to be performed on click of button. And we must have created JavaScript web resource which has the function 'closeForm' to close the form.
  • Replace <CommandDefinitions /> tag with below XML tags.
  • Notice that, CommandDefinition Id must be same as Command in CommandUIDefinition in the above XML.

    <CommandDefinitions>
        <CommandDefinition Id="Account.form.Button.Close.Command">
            <EnableRules>
                <EnableRule Id="Account.form.FormStateNotNew.EnableRule"/>
                <EnableRule Id="Account.form.Field.EnableRule"/>
            <EnableRules/>
            <DisplayRules>
                <DisplayRule Id="Account.form.WebClient.DisplayRule"/>
            </DisplayRules>
            <Actions>
         <JavaScriptFunction Library="$webresource:new_/Scripts/Account.FormClose.jsFunctionName="closeForm"/>
            </Actions>
        </CommandDefinition>
    </CommandDefinitions>


  • Replace <DisplayRules /> in <RuleDefinitions> tag with below tags to define display rules when this button should be visible.

    <DisplayRules>
        <DisplayRule Id="Account.form.WebClient.DisplayRule"/>
            <OrRule>
                <Or>
                    <CrmClientTypeRule Type="Web" />
                </Or>
                <Or>
                    <CrmClientTypeRule Type="Outlook" />
                </Or>
            </OrRule>
        </DisplayRule>
    </DisplayRules>


  • Replace <EnableRules/> in <RuleDefinitions> tag with below tags to define enable rules when this button should be enabled.

   <EnableRules>
        <EnableRule  Id="Account.form.FormStateNotNew.EnableRule">
            <FormStateRule State="Create" InvertResult=="true" />
        </EnableRule>
        <EnableRule Id="Account.form.Field.EnableRule">
            <ValueRule Field="new_formcloseflag" Value=="true" />
        </EnableRule>
    </EnableRules>


  • Save this XML file, Zip it, Import the solution and publish the entity.



Friday, December 14, 2012

Add/Remove a Tab in an entity form using plug-in.

    CRM 2011 allows you to customize the entity form by adding/removing Tabs,Sections,IFrames or Fields programmatically using plug-in/C#. In this example we have two major methods called AddTab and RemoveTab. AddTab will add the new Tab with name "TestTab" which is pointing to an html page 'new_/TestTab.htm' to specified entity form. And RemoveTab method will remove the existing tab with name "TestTab" from the specified entity form.


/// <summary>
/// Method to Add a Tab to entity form.
/// </summary>
/// <param name="entityName">The string.</param>
private void AddTab(string entityName)
{
    Entity entity = GetEntity(entityName);
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(entity.Attributes["formxml"].ToString());
       
    XPathNavigator nav = xmlDoc.CreateNavigator();
    string validateTab = "//tabs/tab[@name='TestTab']";
    string validateTabs = "//tabs";

    string newTab = "<tab name=\"TestTab\" id=\"{3ddb3353-a6ca-3d43-23c2-66ddb019cc50}\" IsUserDefined=\"0\" locklevel=\"0\" showlabel=\"true\" expanded=\"false\">"+
                  "<labels>" +
                  "<label description=\"Test Tab\" languagecode=\"1033\" />" +
                  "</labels>" +
                  "<columns>" +
                  "<column width=\"100%\">" +
                  "<sections>" +
                  "<section name=\"TestTab_Section\" showlabel=\"false\" showbar=\"false\" locklevel=\"0\" id=\"{be95d8ba-6789-d739-4d88-733c9bb914d4}\" IsUserDefined=\"0\" layout=\"varwidth\" columns=\"11\" labelwidth=\"115\" celllabelalignment=\"Left\" celllabelposition=\"Left\">" +
                  "<labels>" +
                  "<label description=\"Test Tab\" languagecode=\"1033\" />" +
                  "</labels>" +
                  "<rows>" +
                  "<row>" +
                  "<cell id=\"{76e6e362-c9d4-1549-25c7-a812d78a16d1}\" showlabel=\"false\" colspan=\"1\" auto=\"false\" rowspan=\"26\">" +
                  "<labels>" +
                  "<label description=\"Entities Test Tab\" languagecode=\"1033\" />" +
                  "</labels>" +
                  "<control id=\"WebResource_EntitiesTestTab\" classid=\"{9FDF5F91-88B1-47f4-AD53-C11EFC01A01D}\">" +
                  "<parameters>" +
                  "<Url>new_/TestTab.htm</Url>" +
                  "<PassParameters>false</PassParameters>" +
                  "<Security>false</Security>" +
                  "<Scrolling>auto</Scrolling>" +
                 "<Border>true</Border>" +
                  "</parameters>" +
                  "</control>" +
                  "<events>" +
                  "<event name=\"onload\" application=\"0\">" +
                  "<dependencies />" +
                  "</event>" +
                  "</events>" +
                  "</cell>" +
                  "</row>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "<row/>" +
                  "</rows>" +
                  "</section>" +
                  "</sections>" +
                  "</column>" +
                  "</columns>" +
                  "</tab>";
       
    XPathNodeIterator iterator = nav.Select(nav.Compile(validateTab));
    if(iterator.Count > 0)
    {
        if(nav.CanEdit)
        {
            XPathNodeIterator xExpression = nav.Compile(validateTabs + "/tab");
            iterator = nav.Select(xExpression);

            if(iterator.Count > 0)
            {
                while(iterator.MoveNext())
                {
                    if(iterator.CurrentPosition == iterator.Count)
                        iterator.Current.InsertAfter(newTab);
                }

                UpdateAndPublishEntityCustomization(entity, entityName, xmlDoc);
            }
        }
    }
}



/// <summary>
/// Method to Add Tab.
/// </summary>
/// <param name="entityName">The string.</param>
private void RemoveTab(string entityName)
{
    Entity entity = GetEntity(entityName);
    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(entity.Attributes["formxml"].ToString());
       
    XPathNavigator nav = xmlDoc.CreateNavigator();
    string validateTab = "//tabs/tab[@name='TestTab']";
    XPathNodeIterator iterator = nav.Select(nav.Compile(validateTab));

    if(iterator.Count > 0)
    {
        if(CheckTab(xmlDoc,"TestTab"))
        {
            XmlNode tabXML = xmlDoc.SelectSingleNode(validateTab);
            if(tabXML != null)
               {
                   tabXML.ParentNode.RemoveChild(tabXML);
                   UpdateAndPublishEntityCustomization(entity, entityName, xmlDoc);
               }
        }
    }
}



/// <summary>
/// Method to retrieve entity.
/// </summary>
/// <param name="entityName">The Entity.</param>
/// <return>The Entity</return>
private Entity GetEntity(string entityName)
{
    RetrieveMultipleResponse results = null;
    RetrieveEntityRequest entityReq = new RetrieveEntityRequest();
    entotyReq.EntityFilters = EntityFilters.Entity;
    entotyReq.LogicalName = entityName;
    RetrieveEntityResponse resp = (RetrieveEntityResponse)service.Execute(entityReq);
    var typeCode = resp.EntityMetadata.ObjectTypeCode.Value;

    QueryExpression query = new QueryExpression("systemform");
    query.ColumnSet = new ColumnSet("formxml");
    query.Criteria.AddCondition(new ConditionExpression("type",ConditionOperator.Equal,2));
    query.Criteria.AddCondition(new ConditionExpression("objecttypecode",ConditionOperator.Equal,typeCode));

    RetrieveMultipleRequest multiReq = new RetrieveMultipleRequest();
    multiReq.Query = query;

    results = (RetrieveMultipleResponse)service.Execute(multiReq);
    Entity entity = results.EntityCollection.Entities.FirstOrDefault();

    return entity;
}



/// <summary>
/// Update the form XML and publish the customization.
/// </summary>
/// <param name="entity">The Entity.</param>
/// <param name="entityName">The string.</param>
/// <param name="xmlDoc">The XmlDocument.</param>
private void UpdateAndPublishEntityCustomization(string entity, string entityName, XmlDocument xmlDoc)
{
    entity.Attributes["formxml"] = xmlDoc.InnerXml;
    service.Update(entity);

    PublishXmlRequest publishXmlReq = new PublishXmlRequest();
    publishXmlReq.ParameterXml = @"<importexportxml>" +
                                  "<entities>" +
                                  "<entity>" + entityName + "</entity>" +
                                  "</entities>" +
                                  "</importexportxml>";
    PublishXmlResponse publishXmlResponse = (PublishXmlResponse)service.Execute(publishXmlReq);
}



/// <summary>
/// Check whether the specified Tab is already exist or not
/// </summary>
/// <param name="xmlDoc">The XmlDoc.</param>
/// <param name="tabName">The string.</param>
private bool CheckTab(XmlDocument xmlDoc, string tabName)
{
    bool present = false;
    XmlNodeList Tabs = xmlDoc.GetElementByTagName("tabs");

    foreach(XmlNode tabs in Tabs)
    {
        foreach(XmlNode tab in tabs)
        {
            XmlAttributeCollection Attributes = tab.Attributes;

            foreach(XmlAttribute Attribute in Attributes)
            {
                if(Attribute.Name = "name" && Attribute.Value = tabName)
                    present = true;
            }
        }
    }
    return present;
}