Monday 23 September 2013

Clone a record in MS CRM 2011 by Mohammad Yusuf Ansari

Sometime in CRM there is a need to copy the existing record.For example there may be a need to clone the existing case so that service representative can update some fields on the cloned case.

Q.How can we achieve it in MS CRM 2011
A. It can be achieved either by JavaScript or Plugin.

We will try to achieve with JavaScript using "Relationships" mappings feature in MS CRM 2011.

Q:What we need to do?
  
1)Add a ribbon button called "Clone Case"
2)Creating a 1:N relationship with Case to Case then generating mappings.
3)On button click Open the URL of the cloned Case.


Implementation:

1)Add a ribbon button called "Clone Case"

Add a ribbon button called "Clone Case".You can use ribbon workbech for this on click of this button it will call a Javascript function called "cloneCase" in "My_CustomRibbonJavascript" webresource.
Or you can do manually like.

1)Create a solution add "Case" entity to it.
2)Export the Solution.
3)Extract the Solution.
4)Open Customizations.xml in Visual studio.
5)Replace <RibbonDiffXmlwith the below given XML
6)Take care of adding the icons as given in below XML in CRM as webresources before import.

<RibbonDiffXml>
  <CustomActions>
 
    <CustomAction Id="My.MSCRM.incident.form.Clone.Button.CustomAction" Location="Mscrm.Form.incident.MainTab.Collaborate.Controls._children" Sequence="0">
      <CommandUIDefinition>
        <Button Command="MSCRM.incident.form.Clone.Command" Id="MSCRM.incident.form.Clone.Button" Image32by32="$webresource:My_Clone32" Image16by16="$webresource:My_Clone16" LabelText="$LocLabels:MSCRM.incident.form.Clone.Button.LabelText" Sequence="0" TemplateAlias="o1" ToolTipTitle="$LocLabels:MSCRM.incident.form.Clone.Button.ToolTipTitle" ToolTipDescription="$LocLabels:MSCRM.incident.form.Clone.Button.ToolTipDescription" />
      </CommandUIDefinition>
    </CustomAction>
 
  </CustomActions>
  <Templates>
    <RibbonTemplates Id="Mscrm.Templates"></RibbonTemplates>
  </Templates>
  <CommandDefinitions>
 
    <CommandDefinition Id="MSCRM.incident.form.Clone.Command">
      <EnableRules/>
      <DisplayRules>
        <DisplayRule Id="MSCRM.incident.form.Clone.DisplayRule" />
      </DisplayRules>
      <Actions>
        <JavaScriptFunction FunctionName="cloneCase" Library="$webresource:My_CustomRibbonJavascript" />
      </Actions>
    </CommandDefinition>
 
  </CommandDefinitions>
  <RuleDefinitions>
    <TabDisplayRules />
    <DisplayRules>
 
      <DisplayRule Id="MSCRM.incident.form.Clone.DisplayRule">
        <FormStateRule State="Create" InvertResult="true" />
      </DisplayRule>
 
    </DisplayRules>
    <EnableRules/>
 
  </RuleDefinitions>
  <LocLabels>
 
    <LocLabel Id="MSCRM.incident.form.Clone.Button.LabelText">
      <Titles>
        <Title description="Clone Case" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="MSCRM.incident.form.Clone.Button.ToolTipDescription">
      <Titles>
        <Title description="Clone Case" languagecode="1033" />
      </Titles>
    </LocLabel>
    <LocLabel Id="MSCRM.incident.form.Clone.Button.ToolTipTitle">
      <Titles>
        <Title description="Clone Case" languagecode="1033" />
      </Titles>
    </LocLabel>
 
  </LocLabels>
</RibbonDiffXml>

2)Creating a 1:N relationship with Case to Case then generating mappings.

Open the Case enity relationship(1:N) and Create a relationship with Case.Open the created relationship and generate mappings.

Refer below screenshots











3)On button click Open the URL of the cloned Case.

Add a new webresource called "My_CustomRibbonJavascript" add the  "cloneCase" function to it


function GetContext() {
    var _context = null;
    if (typeof GetGlobalContext != "undefined")
        _context = GetGlobalContext();
    else if (typeof Xrm != "undefined")
        _context = Xrm.Page.context;
    return _context
}
function cloneCase() {
 
    if (Xrm.Page.data.entity.getId() == null) {
        alert('First save the record before Clone Case')
 
    }
    else {
        var CRMContext = GetContext();
        var serverUrl = CRMContext.getServerUrl();
        var caseid = Xrm.Page.data.entity.getId();
        caseid = caseid.replace('{''').replace('}''');
 
        //Below URL is for CRM online  
        var url = serverUrl + 'main.aspx?etc=112&extraqs=%3f_CreateFromId%3d%257b' + caseid + '%257d%26_CreateFromType%3d112%26etc%3d112%26pagemode%3diframe&pagetype=entityrecord';
 
        openNewWindow(url, 900, 600, 'toolbar=no,menubar=no,resizable=yes');
    }
 
 
}


Note:How to create the URL

Since Case is in 1:N relationship It will appear in case left navigation pane.Click on Case button and add the new Case.Copy the created URL and make it dynamic.

For Onpresmise MS CRM 2011 URL will be like this

var url = serverUrl + '/cs/cases/edit.aspx?_CreateFromType=112&_CreateFromId=' +
 Xrm.Page.data.entity.getId();



 Hope it helps someone somewhere :)

Regards,

Yusuf

Clone an Opportunity in MS CRM 2011 with Plugin by Mohammad Yusuf Ansari

Below is a Plugin to create an Opportunity Clone [Cloning opportunity products as well].It uses early bound approach.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Crm.Sdk.Messages;
using Entities = Pes.My.Configurations.Entities;
using System.ServiceModel;
using Pes.My.Configurations.Entities;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Client;
 
namespace My.Crm.Plugins.Opportunity
{
    public class PostUpdate : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            Entities.Opportunity oppRec;
 
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
 
            // This plug-in was fired from the playback queue after the user selected to go online within Microsoft Dynamics CRM for Outlook.
            if (context.IsExecutingOffline || context.Depth > 1)
                return;
 
 
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"is Entity)
            {
 
                //Verify that the entity represents an Opportunity
                if (((Entity)context.InputParameters["Target"]).LogicalName != Pes.My.Configurations.Entities.Opportunity.EntityLogicalName || context.MessageName != "Update")
                    return;
                else
                    oppRec = ((Entity)context.InputParameters["Target"]).ToEntity<Pes.My.Configurations.Entities.Opportunity>();
            }
            else
            {
                return;
            }
 
            try
            {
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
 
 
                using (var MyContext = new MyContext(service))
                {
 
                    if (oppRec.My_IsCloned == true)
                    {
                        if (context.Depth == 1)
                        {
 
                            Entity opportunity = null;
 
                            opportunity = service.Retrieve(Entities.Opportunity.EntityLogicalName, oppRec.Id, new ColumnSet(true));
 
                            Entity cloneopportunity = new Entity();
 
                            opportunity.Attributes.Remove("opportunityid");
                            opportunity.Id = Guid.NewGuid();
 
                            cloneopportunity = opportunity;
                            Guid ClonedOppId = service.Create(cloneopportunity);
 
 
                            List<Entities.OpportunityProduct> listoppproduct = MyContext.OpportunityProductSet
                                      .Where(acp => acp.OpportunityId.Id == oppRec.Id).ToList<Entities.OpportunityProduct>();
                            foreach (OpportunityProduct objoppproduct in listoppproduct)
                            {
                                cloneOppProduct((Guid)objoppproduct.Id, ClonedOppId, service);
                            }
 
 
                        }
 
                    }
 
                }
 
 
            }
            catch (InvalidPluginExecutionException)
            {
                throw;
            }
            catch (FaultException<OrganizationServiceFault> ex)
            {
                throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
            }
 
        }
 
        private void cloneOppProduct(Guid guid, Guid Opp, IOrganizationService service)
        {
 
            Entity opportunityproduct = null;
            opportunityproduct = service.Retrieve(Entities.OpportunityProduct.EntityLogicalName, guid, new ColumnSet(true));
 
            Entity cloneopportunityproduct = new Entity();
 
            opportunityproduct.Attributes.Remove("opportunityproductid");
            opportunityproduct.Attributes.Remove("opportunityid");
            opportunityproduct.Id = Guid.NewGuid();
            opportunityproduct.Attributes["opportunityid"] = new EntityReference(Entities.Opportunity.EntityLogicalName, Opp);
            cloneopportunityproduct = opportunityproduct;
            service.Create(cloneopportunityproduct);
 
        }
    }
}



Note: I run this plugin from ribbon button "Clone Opportunity".Here I am setting Custom field "My_IsCloned " to true and saving the form using javaScript.And On post update it triggers this plugin.


Also you have to create an early bound class using CrmSvcUtil  below is an example

CrmSvcUtil.exe /out:MyEntities.cs /url:https://Mydev1.api.crm.dynamics.com/XRMServices/2011/Organization.svc /username:name@My.com /password:pass123 /namespace:Pes.My.Configurations.Entities /serviceContextName:MyContext 

Use the class generated i.e MyEntities [here] in your project and accomplish the same.

Hope this helps.

LINQ query to get all the N:N custom entity records for the above Account.



 string accountId = "CC572EC9-01E3-E211-AC62-984BE173A384";
  var customEntities = (from NtoN in makeUseOfContext.new_customentity_accountSet
                        where NtoN.accountid.Value == new Guid(accountId) && 
                        NtoN.new_customentityid != null
                         select new { 
                                    customentityid = NtoN.new_customentityid.Value 
                                   }).ToList();

C# code to create a email record in MSCRM 2011


                    Entity email = new Entity();
                    email.LogicalName = "email";

                    //Set regarding object property (i.e. The entity record, which u want this email associated with)

                    EntityReference regardingObject = new EntityReference("quote", targetEntity.Id);
                    email.Attributes.Add("regardingobjectid", regardingObject);

                    //Defining Activity Parties (starts)
                    //Derive ccparty

                  EntityReference cc1 = new EntityReference("systemuser", preparedById);
                    EntityReference cc2 = new EntityReference("systemuser", salesContactId);


                    Entity ccParty = new Entity("activityparty");
                    ccParty.Attributes.Add("partyid", cc1);
                    Entity ccParty1 = new Entity("activityparty");
                    ccParty1.Attributes.Add("partyid", cc2);

                    EntityCollection collccParty = new EntityCollection();
                    collccParty.EntityName = "systemuser";
                    collccParty.Entities.Add(ccParty);
                    collccParty.Entities.Add(ccParty1);
                    EntityCollection collToParty = new EntityCollection();
                    collToParty.EntityName = "contact";
                    collToParty.Entities.Add(toParty);
      //Derive to party
                    email.Attributes.Add("cc", collccParty);
                    Entity toParty = new Entity("activityparty");
                    EntityCollection contacts = GetContactsRelatedTOQuote(service, targetEntity.Id);
                    if (contacts.Entities.Count > 0)
                    {
                        foreach (Entity e in contacts.Entities)
                        {
                            toParty.Attributes.Add("partyid", new EntityReference("contact", e.Id));
                        }

                    }

                    email.Attributes.Add("to", collToParty);

                    //Defining Activity Parties (ends)

                    //Set subject & body properties
                    email.Attributes.Add("subject", "xxxxxx " + postMessageImage["name"].ToString());
                    email.Attributes.Add("description", "Test");

                    //Create email activity

                    Guid emailID = service.Create(email);

Calling On Demand Workflow through a Button in Ribbon (launchOnDemandWorkflow) in CRM 2011 by Nishanth Rana

l had to call  an on demand workflow through a custom button click inside the ribbon. I thought of using launchOnDemandWorkflow function.
But couldn’t really find a way of calling that function.
So thought of calling it through its url, which would be something like this

iObjType=10004
&iTotal=1
&sIds=%7b4BEBDCAF-8F66-E011-A475-00155D045711%7d%3b
&wfId=%7bF0ED25C7-5129-4297-8515-69DFFA0739FF%7d

function CallOnDemandWorkflow() {

var recordID = crmForm.ObjectId;

var url = http://server/org/_grid/cmds/dlg_runworkflow.aspx?iObjType=10004&iTotal=1&sIds={“+ recordID + “}&wfId={F0ED25C7-5129-4297-8515-69DFFA0739FF}”;
window.open(url);
}
However I keep getting some JavaScript Error.
Finally found out the correct way of doing so.
function CallOnDemandWF() {
var a = new Array(crmFormSubmit.crmFormSubmitId.value);
var sIds = crmFormSubmit.crmFormSubmitId.value+“;”;
var sEntityTypeCode = “10004″//Replace this with your entity type code
var sWorkflowId = “{F0ED25C7-5129-4297-8515-69DFFA0739FF}”//Replace this with your actual workflow ID
var iWindowPosX = 500; //Modal dialog position X
var iWindowPosY = 200; //Modal dialog position Y
var oResult = openStdDlg(prependOrgName(“/_grid/cmds/dlg_runworkflow.aspx”)+“?iObjType=” + CrmEncodeDecode.CrmUrlEncode(sEntityTypeCode) + “&iTotal=” +
CrmEncodeDecode.CrmUrlEncode(a.length) + “&wfId=” + CrmEncodeDecode.CrmUrlEncode(sWorkflowId)+ “&sIds=” + CrmEncodeDecode.CrmUrlEncode(sIds) , a, iWindowPosX, iWindowPosY);
}
Check out the thread
Final Output