Monday, 23 September 2013

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

Creating email using Rest Javascript call In MSCRM 2011

How to create an email activity using REST Endpoints in CRM2011


How tough it can be to create an activity using code? It sounds very easy but there are few issues, if you are using REST Endpoints.

REST Endpoints do not support all the CRM data types. One of those data type is PartyList. PartyList is very important to create most of the activity like emails, appointments, phone calls etc.

To set the value of the PartyList field you need an array of PartyLists as you can have more than value for those fields. For e.g you can have more than one recipient for an email or you can have more than resource for an appointment.

As I mentioned earlier, REST Endpoints do not support PartyList, So its is impossible to assign value to these fields. If you look at DataSet returned by the Rest Endpoints, It looks like they are treating PartyList fields like string fields.

image

These values does not even return the guid or name of the PartyList entity. if you look at sender field in the screen shot above, it does not have guid or the name of the system user who sent this email.
I tried the same using following code:

email.Sender="crm2011@emailops.com.au";
var partlistcollection = new Array(); //tried to create an array of PartyLists

partlistcollection[0] = {Id: "8384E684-7686-E011-8AF0-00155D32042E",LogicalName: "contact",Name: "Amreek Singh"};
email.ToRecipients=JSON.stringify(partlistcollection);

But it did not work, if you pass a string value to the PartyList fields, You won’t get any error message but you won’t see any value in those fields on a created entity.

Now here is the solution. You need to create an activity (in this case it’s  an email) first and then create a PartyList entity and link it back to the created activity.

function CreateEmail() {
alert("CreateEmail Begin");

var email = new Object();
email.Subject = "Sample Email Using REST";
SDK.JScriptRESTDataOperations.Create(email, "Email", EmailCallBack, function (error) { alert(error.message); });
}

// Email Call Back function
function EmailCallBack(result)
{
var activityParty=new Object();
// Set the "party" of the ActivityParty // EntityReference of an entity this activityparty relatated to. 
activityParty.PartyId = {
  Id: "8384E684-7686-E011-8AF0-00155D32042E",//replace this with the contactid from your system.
  LogicalName: "contact"
};
// Set the "activity" of the ActivityParty
// EntityReference.
activityParty.ActivityId = {
  Id: result.ActivityId, 
  LogicalName: "email"
};
// Set the participation type (what role the party has on the activity).
activityParty.ParticipationTypeMask = { Value: 2 }; // 2 mean ToRecipients
SDK.JScriptRESTDataOperations.Create(activityParty, "ActivityParty",ActivityPartyCallBack , function (error) { alert(error.message); });
}

function ActivityPartyCallBack(reuslt)
{
alert("Process Completed");
}
activityParty.ParticipationTypeMask = { Value: 2 }; is very important as it will specify if this PartList is sender/recipient/resource etc  of the activity.

Here is the link to complete list of activityParty.ParticipationTypeMask click here.
For this sample, I have used the generic REST CRUD data operations library created by Jim Daly.
Add references to following Java Script  web resources to try the solution.
  • SDK.JScriptRESTDataOperations
  • JSON2
Here is the link to unmanaged solution RESTEmailSolution_1_0
  • I hope this helps.