Friday 24 May 2013

Clone an Opportunity in MS CRM 2011 by Plugin.

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.

Yusuf

3 comments:

  1. I tried what you said above but i am getting error while creating new entity.error is "Generic SQL error".this is my code
    Entity newAccount = null;
    Entity oldAccount = new Entity();
    oldAccount = service.Retrieve("account", AccountID, new ColumnSet(true));
    if (oldAccount != null)
    {
    oldAccount .Attributes.Remove("accountid");
    oldAccount .Id = Guid.NewGuid();
    newAccount = oldAccount ;
    Guid accountID = service.Create(newAccount);
    }

    ReplyDelete
  2. Could u please give any solution for this?

    ReplyDelete
  3. context.Depth > 1 is very much a valid scenario and should not be used as a check against looping. If you had a plugin on save of one entity that creates or updates a second entity, any messages registered on that second entity would have a context of 2. Same can apply to workflow triggering during data import etc.

    The system will automatically error out if the depth > 8. There's no reason to check the depth for looping unless you have bad code / logic.

    ReplyDelete