Clone any Record Dynamics 365

Hello Everyone,

I was working on a requirement where i have to clone records on multiple custom entities.if the entity having very less fields, you can achieve it easily but what about those entities where attributes are more than 100 per entity. So, i am going to tell you how you can achieve it easily by writing a very small code.

Lets start!

Step-1: Add a button “Clone” using the ribbon workbench on your entity where you want to perform the cloning. Just drag and drop where you want to add.

Now create a command and add an java script action.

Add java script library and function name(code added below). Add a “Crm Parameter= PrimaryControl”.

After that add the command to the button. Publish the solution from ribbon workbench.

Step-2: Now create a global Action process inside your dynamics solution.and create a input parameter of “Entity” type .

we are going to set it through our java script code as below. So while setting the entity type parameter inside the action, we need to specify two properties , 1) GUID of the record , 2) Logical name in key value pair.

Note: Value you can get easily but how you can make “key” dynamic so that it could run on any custom entity. for that you need to pass the key dynamically as shown in below code(check InvokeAction function parameter).

function callAction(primaryControl) {
    debugger;
    var formContext=primaryControl;
    var formtype = formContext.ui.getFormType();
    if(formtype!=1){
    debugger;
    Xrm.Utility.confirmDialog("Do You want Clone this Record?", 
    function () {
     var recordId = formContext.data.entity.getId().replace("{", "").replace("}", "");
     var logicalName = formContext.data.entity.getEntityName();
    InvokeAction(recordId,logicalName);
    },
    function () {});
    
    } 
   }
   function InvokeAction(recordId,logicalName) {
    debugger;
    var parameters = {};
var target = {};
target[logicalName+"id"]=recordId;      //making it dynamics so can be worked on multiple entity
target["@odata.type"] = "Microsoft.Dynamics.CRM."+logicalName;
parameters.Target = target;

var ign_CloneRecordRequest = {
    Target: parameters.Target,

    getMetadata: function() {
        return {
            boundParameter: null,
            parameterTypes: {
                "Target": {
                    "typeName": "mscrm.crmbaseentity",
                    "structuralProperty": 5
                }
            },
            operationType: 0,
            operationName: "ign_CloneRecord"            //specify your action name
        };
    }
};

Xrm.WebApi.online.execute(ign_CloneRecordRequest).then(
    function success(result) {
        if (result.ok) {
            //Success - No Return Data - Do Something
        }
    },
    function(error) {
        Xrm.Utility.alertDialog(error.message);
    }
);
    
   }
   

Step-3:After that you need to create a plugin which will create a clone/copy of the record.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;

namespace cloneRecord
{
    public class cloneRecord : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            IOrganizationServiceFactory servicefactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = servicefactory.CreateOrganizationService(context.UserId);
            tracing.Trace(context.InputParameters.Contains("Target").ToString());
            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                if(context.Depth>1)
                {
                    return;
                }
                //Getting the Entity record from the Action
                Entity en = (Entity)context.InputParameters["Target"];
                //Retrieving the same entity record with all the attributes
                Entity entity= service.Retrieve(en.LogicalName, en.Id, new ColumnSet(true));
                //Set the EntityState to null, so that a new cloned record can be created
                entity.EntityState = null;
                //remove the PrimaryId of the record otherwise will show you error
                entity.Attributes.Remove(entity.LogicalName+"id") ;

                if(entity.Contains("new_name") && (string)entity.Attributes["new_name"]!=string.Empty)
                {
                    //differentiating the new record which will create from the exisiting with New prefix.
                    entity.Attributes["name"] = "New " + entity.Attributes["name"].ToString();
                }

                //set a unique id to the cloned record
                entity.Id = Guid.NewGuid();

                //Create the new cloned record
                service.Create(entity);
            }
            }
    }
}

Now register your plugin and use the global action as message inside your plugin step.

Now navigate to custom entity in dynamics model driven app. As you can see here my clone button just click on it.

Now go back to the Entity list record and you will found copied/cloned record as below image. If you want to do cloning of record more than one entity, just follow only the Step-1 as shown above, it will work for any entity.

That’s it.

Hope this will help you. If you having any issues please feel free to ask me . Shoot your question in comment box.

Sharing A Record with Different Business Unit Teams

Hello Everyone,

I was working on a requirement where i need to share records in different business unit teams. So i am sharing my knowledge how i achieve it using owner team.

First thing i am creating a security role in root business unit and give the right permission and access to entity “Account1”.

Create teams in those child BU where you want to share the records. I have created a Child BU as Bangalore. Create a teams in Child BU.

Assign the security role to Teams which you have created.(You will see Root BU security roles in every business unit because child BU Security roles inherit the parent roles.)

I have an entity name as “Account1” in which having a lookup of business unit. On record creation the record will be share to the respected team e.g. “Account1 Team”. To achieve this functionality i am going to right a custom workflow and calling it under OOB workflow.

Here is my custom code activity.

using System;
using System.Activities;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Workflow;

namespace shareAccount1
{
    public class shareAccount1: CodeActivity
    {
        [RequiredArgument]
        [Input("Send To")]
        [ReferenceTarget("businessunit")]
        public InArgument<EntityReference> sendTo { get; set; }

        protected override void Execute(CodeActivityContext context)
        {
            ITracingService tracingService = (ITracingService)context.GetExtension<ITracingService>();
            IWorkflowContext workflowContext = (IWorkflowContext)context.GetExtension<IWorkflowContext>();
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)context.GetExtension<IOrganizationServiceFactory>();
            IOrganizationService service = serviceFactory.CreateOrganizationService(workflowContext.UserId);
            var buname = this.sendTo.Get<EntityReference>(context);
            EntityReference UserRef = null;
            Entity targetEntity = (Entity)workflowContext.InputParameters["Target"];
            Guid CTIId = targetEntity.Id;
            string entityLogicalName = targetEntity.LogicalName;
            Guid businessunitlookupid = buname.Id;
            //Guid businessunitlookupid = ((EntityReference)targetEntity.Attributes["new_sendto"]).Id;

            QueryExpression queryExpression = new QueryExpression("team");
            queryExpression.ColumnSet.AddColumns("name", "teamid", "businessunitid");
            queryExpression.Criteria = new FilterExpression();
            queryExpression.Criteria.AddCondition("name", ConditionOperator.Equal, "Account1 Team");
            queryExpression.Criteria.AddCondition("businessunitid", ConditionOperator.Equal, businessunitlookupid);

            EntityCollection entityCollection = service.RetrieveMultiple(queryExpression);
            if (entityCollection.Entities.Count > 0)
            {
                foreach (Entity teamEntity in entityCollection.Entities)
                {

                    UserRef = new EntityReference(teamEntity.LogicalName, teamEntity.Id);
                }
            }
            var recordRef = new EntityReference(targetEntity.LogicalName, targetEntity.Id);

            // Principal – for whom we are sharing  the record.

            // Target – Which record we are sharing.

            //Sharing a RECORD
            GrantAccessRequest request = new GrantAccessRequest
            {
                PrincipalAccess = new PrincipalAccess
                {
                    AccessMask = AccessRights.ReadAccess|AccessRights.WriteAccess ,
                    Principal = UserRef
                },
                Target = recordRef
            };
            service.Execute(request);


            // throw new NotImplementedException();
        }

    }
}


Register your code activity using plugin registration tool. create a OOB workflow and select your workflow from the steps.

Set the property as below. As i earlier mentioned i have a lookup field on my form which is Send To, which i am setting in the input parameter of workflow.

Once it is done activate your workflow and test.I created a record new record “TestShare1” where owner of the record is Venkateshwararoa. Once it is created it will share the record to team member of different BU.

After creation , record is shared with Surya Singh as member of the Account1 Team.

That’s it. Shot comment on the blog if you facing any challenges.

Hide and Show Ribbon Button Based on User Security Role in Dynamics 365 v9.x

Hello Everyone, Today i would like to share my knowledge regarding show and hide ribbon button based on the user Security roles.

I have a custom entity name as “account1”. I have to create two button (Submit, Complete) using ribbon workbench.We have two type of user one is Salesperson, second one Sales Manager. So in this blog i am going to cover some of the points as given below.

1.If user security role is Salesperson, show “Submit” button and hide the “Complete” button.

2.If user security role is Sales Manager, show “Complete” button and hide the “Submit” button.

3.After creation of the record user will able to see the buttons(Submit or Complete).

Lets start.

I created a solution named as AccounRibbon and added my entity account1. Import the latest ribbon workbench into your organisation if already not done. Once it is imported successfully, open the the ribbon workbench and select your solution, i am selecting the  Account Ribbon.

1

Once your solution loaded successfully,select the entity and add the buttons in to main form by drag and drop. Give the proper names to buttons.

2

once button added we need to add the command and the enable rules for both the buttons.

3

Lets first talk about the Enable Rules.In Simple words, Enable rule are used as trigger when our buttons will enable for form.So first we need to check both the button will available only when the form type is update, for that we are going to use form state rule.

Click on the Submit Enable rule as shown in above screenshot, on the right panel , click on add step and choose FormStateRule.

4
5

Use existing because we want show this button after the record is created. Set invert rule as true, it means if the form is not “Existing” type then button will hide automatically. Same step follow for the Completed Enable rule. once both is done , now we have to write a CustomRule that will check the user security role and based on the user security role we will return true or false from the function.

NOTE:Please don’t focus on the other two ValueRule  i am doing some other calculation as well that is not part of the this blog.

create a web resource and add this JS in your web resource.

function getCurrentUserSecurityRolesIfsalesperson()
{
    debugger;
    var value=false;
    var userRoles=Xrm.Utility.getGlobalContext().userSettings;
    if(Object.keys(userRoles.roles._collection).length>0)
    {
        for ( var rolidcollection in userRoles.roles._collection)
        {
           var currentUserRoles= Xrm.Utility.getGlobalContext().userSettings.roles._collection[rolidcollection].name;    
           if(currentUserRoles.toLowerCase()=="salesperson")
           {
               value=true;
               break;
           }
        }
    }
    return value; 
}

After adding this JS publish the web resource and go back to the ribbon workbench.

Add new Step in Enable rule and select custom rule. Specify the property as shown in image.

This is completed for one button submit repeat the same process for complete button do necessary changes.e.g match with sales manager role like i am matching with salesperson.

Now you have both the enable rule done. Add both the enable rule to respected command as shown in below image.

Once it is added. you can specify the action-> what you want to perform after click on button. as given in the snap. Perform the same steps for the Complete command as well. Now go to the button tab select the button and add the command respected to your button.

Once the command added , perform same operation for the Submit button.then click on publish.

Once you follow all the steps you will easily achieve what i shared in blog.

Thanks for seeing. Hope you like it. If you have any query please use comment box.