Clone a record with a button: Part 2 – Plugin

using System;
using System.Linq;
using System.ServiceModel;
using Microsoft.Crm.Sdk.Messages;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace HR_Center_BR_Vertragsdetails
{
    public class CopyCloneTool : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the tracing service
            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            // Obtain the execution context from the service provider.  
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Check if the custom message contains the necessary parameters
            if (context.InputParameters.Contains("cloneConfiguration") && context.InputParameters.Contains("guid"))
            {
                // Obtain the IOrganizationService instance which you will need for web service calls.  
                IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

                try
                {
                    string cloneConfiguration = context.InputParameters["cloneConfiguration"] as string;
                    Guid sourceGuid = new Guid(context.InputParameters["guid"] as string);

                    QueryExpression queryCloneConfiguration = new QueryExpression("ppt_cloneconfiguration");
                    queryCloneConfiguration.ColumnSet.AddColumns("ppt_purpose", "ppt_targetentity", "ppt_sourceentity", "ppt_sourceattributes", "ppt_targetattributes");
                    queryCloneConfiguration.Criteria.AddCondition("ppt_purpose", ConditionOperator.Equal, cloneConfiguration);
                    EntityCollection resultCloneConfiguration = service.RetrieveMultiple(queryCloneConfiguration);

                    if (resultCloneConfiguration != null && resultCloneConfiguration.Entities.Count > 0)
                    {
                        Entity cloneConfig = resultCloneConfiguration.Entities[0];
                        string targetEntity = cloneConfig.GetAttributeValue<string>("ppt_targetentity");
                        string sourceEntity = cloneConfig.GetAttributeValue<string>("ppt_sourceentity");
                        string sourceAttributes = cloneConfig.GetAttributeValue<string>("ppt_sourceattributes");
                        string targetAttributes = cloneConfig.GetAttributeValue<string>("ppt_targetattributes");

                        // Split the source and target attributes into arrays and trim spaces
                        string[] sourceAttributesArray = sourceAttributes.Split(',').Select(attr => attr.Trim()).ToArray();
                        string[] targetAttributesArray = targetAttributes.Split(',').Select(attr => attr.Trim()).ToArray();

                        // Ensure the source and target attributes arrays have the same length
                        if (sourceAttributesArray.Length == targetAttributesArray.Length)
                        {
                            // Log the source attributes array
                            tracingService.Trace("Source Attributes Array: " + string.Join(", ", sourceAttributesArray));

                            // Retrieve the source entity
                            Entity sourceEntityRecord = service.Retrieve(sourceEntity, sourceGuid, new ColumnSet(sourceAttributesArray));

                            // Create the target entity
                            Entity targetEntityRecord = new Entity(targetEntity);

                            // Map the attributes from the source entity to the target entity
                            for (int i = 0; i < sourceAttributesArray.Length; i++)
                            {
                                string sourceAttribute = sourceAttributesArray[i];
                                string targetAttribute = targetAttributesArray[i];

                                tracingService.Trace($"Mapping source attribute '{sourceAttribute}' to target attribute '{targetAttribute}'.");

                                if (sourceEntityRecord.Contains(sourceAttribute))
                                {
                                    targetEntityRecord[targetAttribute] = sourceEntityRecord[sourceAttribute];
                                }
                                else
                                {
                                    tracingService.Trace($"Source entity does not contain attribute '{sourceAttribute}'.");
                                }
                            }

                            // Create the target entity record in CRM
                            service.Create(targetEntityRecord);

                            // Deactivate the source entity
                            SetStateRequest deactivateRequest = new SetStateRequest
                            {
                                Entity Moniker = new EntityReference(sourceEntity, sourceGuid),
                                State = new OptionSetValue(1), // 1 typically represents 'Inactive'
                                Status = new OptionSetValue(-1) // -1 to use the default status
                            };
                            service.Execute(deactivateRequest);

                            // Set the output parameter
                            tracingService.Trace("Setting output parameter CloneResultMessage.");
                            context.OutputParameters["CloneResultMessage"] = "Entity duplicated and source deactivated successfully.";

                        }
                        else
                        {
                            throw new InvalidPluginExecutionException("Source and target attributes count mismatch.");
                        }
                    }
                    else
                    {
                        throw new InvalidPluginExecutionException("Clone configuration not found.");
                    }

                    tracingService.Trace("HR_Center_BR_copy: Entity duplicated and source deactivated successfully.");
                }
                catch (FaultException<OrganizationServiceFault> ex)
                {
                    throw new InvalidPluginExecutionException("An error occurred during the copy of the contract details.", ex);
                }
                catch (Exception ex)
                {
                    tracingService.Trace("HR_Center_BR_copy: {0}", ex.ToString());
                    throw;
                }
            }
            else
            {
                throw new InvalidPluginExecutionException("Required parameters are missing.");
            }
        }
    }
}