protected override void ExecuteInternal(LocalWorkflowContext context)
        {
            var stageNameToSet = this.StageNameInArgument.Get(context.CodeActivityContext).ToUpper();

            RetrieveProcessInstancesRequest retrieveProcessInstancesRequest = new RetrieveProcessInstancesRequest
            {
                EntityId          = context.WorkflowContext.PrimaryEntityId,
                EntityLogicalName = context.WorkflowContext.PrimaryEntityName
            };

            RetrieveProcessInstancesResponse retrievedProcessInstancesResponse = (RetrieveProcessInstancesResponse)context.OrganizationService.Execute(retrieveProcessInstancesRequest);

            var     activeProcessInstance = retrievedProcessInstancesResponse.Processes.Entities[0]; // First record is the active process instance
            var     workflowReference     = (EntityReference)activeProcessInstance.Attributes["processid"];
            Process workflow = context.OrganizationService.Retrieve(workflowReference.LogicalName, workflowReference.Id, new ColumnSet(true)).ToEntity <Process>();

            RetrieveActivePathRequest pathRequest = new RetrieveActivePathRequest
            {
                ProcessInstanceId = activeProcessInstance.Id
            };

            RetrieveActivePathResponse pathResponse = (RetrieveActivePathResponse)context.OrganizationService.Execute(pathRequest);
            var stageToSetId = (Guid)pathResponse.ProcessStages.Entities.Where(x => x.Attributes["stagename"].ToString().ToUpper() == stageNameToSet).First().Attributes["processstageid"];

            ColumnSet columns = new ColumnSet();

            columns.AddColumn("activestageid");
            Entity retrievedProcessInstance = context.OrganizationService.Retrieve(workflow.UniqueName, activeProcessInstance.Id, columns);

            // Set the next stage as the active stage
            retrievedProcessInstance["activestageid"] = new EntityReference(ProcessStage.EntityLogicalName, stageToSetId);
            context.OrganizationService.Update(retrievedProcessInstance);
        }
        public static Entity[] GetActivePath(CrmTestingContext crmContext, Entity instance)
        {
            var req = new RetrieveActivePathRequest()
            {
                ProcessInstanceId = instance.Id
            };

            return(GlobalTestingContext.ConnectionManager.CurrentConnection.Execute <RetrieveActivePathResponse>(req).ProcessStages.Entities.ToArray());
        }
Esempio n. 3
0
        public static void ChangeStage(IOrganizationService service, Guid op)
        {
            // Get Process Instances
            RetrieveProcessInstancesRequest processInstanceRequest = new RetrieveProcessInstancesRequest
            {
                EntityId          = op,
                EntityLogicalName = Opportunity.EntityLogicalName
            };

            RetrieveProcessInstancesResponse processInstanceResponse = (RetrieveProcessInstancesResponse)service.Execute(processInstanceRequest);

            // Declare variables to store values returned in response
            int    processCount            = processInstanceResponse.Processes.Entities.Count;
            Entity activeProcessInstance   = processInstanceResponse.Processes.Entities[0]; // First record is the active process instance
            Guid   activeProcessInstanceID = activeProcessInstance.Id;                      // Id of the active process instance, which will be used later to retrieve the active path of the process instance

            // Retrieve the active stage ID of in the active process instance
            Guid activeStageID = new Guid(activeProcessInstance.Attributes["processstageid"].ToString());

            // Retrieve the process stages in the active path of the current process instance
            RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
            {
                ProcessInstanceId = activeProcessInstanceID
            };
            RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)service.Execute(pathReq);


            // Retrieve the stage ID of the next stage that you want to set as active
            activeStageID = (Guid)pathResp.ProcessStages.Entities[4].Attributes["processstageid"];

            // Retrieve the process instance record to update its active stage
            ColumnSet cols1 = new ColumnSet();

            cols1.AddColumn("activestageid");
            Entity retrievedProcessInstance = service.Retrieve("opportunitysalesprocess", activeProcessInstanceID, cols1);

            // Set the next stage as the active stage
            retrievedProcessInstance["activestageid"] = new EntityReference(OpportunitySalesProcess.EntityLogicalName, activeStageID);
            service.Update(retrievedProcessInstance);
        }
        private void btnMigrateRecordBPF_Click(object sender, EventArgs evt)
        {
            if (!AllowMigrateButton())
            {
                return;
            }

            string        bpfSelectedEntityTarget = bpfSelected.Attributes["uniquename"].ToString();
            var           stageId              = stageList.FirstOrDefault(w => w.Attributes["stagename"] == cbTargetBPFStages.SelectedItem);
            List <string> traversedpath        = new List <string>();
            string        targetStage          = cbTargetBPFStages.SelectedItem.ToString();
            var           totalRecordMigrated  = 0;
            var           totalRecordInstanced = 0;
            var           totalRecordUpdated   = 0;
            var           totalSkipped         = 0;

            totalRecordToMigrate = userList.Count * recordToMigrateList.Count;
            migrationErrors      = new List <MigrationError>();

            manageEnablingOfControls(false);
            DisplayStatsMiddle();

            // Init progressBar

            SendMessageToStatusBar(this, new StatusBarMessageEventArgs(0, "Starting migration ..."));

            WorkAsync(new WorkAsyncInfo
            {
                Message      = $"Migrating the Business Process flows for each users and records {Environment.NewLine}May take a moment ...",
                IsCancelable = true,
                Work         = (bw, e) =>
                {
                    List <Entity> retrieveExistingBPFInstances = null;
                    try
                    {
                        retrieveExistingBPFInstances = dm.GetExistingBPFInstances(bpfSelected.GetAttributeValue <string>("uniquename"),
                                                                                  recordToMigrateList.FirstOrDefault().LogicalName, recordToMigrateList.Select(x => x.Id).ToArray());
                    }
                    catch (Exception exception)
                    {
                        if (!continueOnPermissionError)
                        {
                            var result = MessageBox.Show(exception.Message, "Error during migration !",
                                                         MessageBoxButtons.YesNo, MessageBoxIcon.Error);

                            if (result == DialogResult.No)
                            {
                                return;
                            }
                            else if (result == DialogResult.Yes)
                            {
                                continueOnPermissionError = true;
                            }
                        }
                    }


                    var userProceed = 1;
                    int progress    = ((((totalRecordUpdated + totalRecordInstanced) / 2) * 100) / totalRecordToMigrate);
                    foreach (var user in userList)
                    {
                        if (bw.CancellationPending)
                        {
                            e.Cancel = true;
                            break;
                        }

                        var numberOfRecordsToProceed = recordToMigrateList.Count;
                        var recordInstanced          = 0;
                        var recordUpdated            = 0;

                        var executeMultipleRequestSetBPF = new ExecuteMultipleRequest()
                        {
                            Settings = new ExecuteMultipleSettings()
                            {
                                ContinueOnError = false,
                                ReturnResponses = true
                            },
                            Requests = new OrganizationRequestCollection()
                        };

                        // Instancing the BPF first
                        foreach (var record in recordToMigrateList)
                        {
                            if (bw.CancellationPending)
                            {
                                e.Cancel = true;
                                break;
                            }

                            // Create the instance of the BPF on the record
                            SetProcessRequest setProcReq = new SetProcessRequest
                            {
                                Target     = record.ToEntityReference(),
                                NewProcess = new EntityReference(bpfSelected.LogicalName, bpfSelected.Id),
                            };

                            var existingBPFInstance = retrieveExistingBPFInstances.FirstOrDefault(x => x.GetAttributeValue <EntityReference>("bpf_" + record.LogicalName + "id")?.Id == record.Id || x.GetAttributeValue <EntityReference>(record.LogicalName + "id")?.Id == record.Id);
                            if (existingBPFInstance != null)
                            {
                                setProcReq.NewProcessInstance = new EntityReference("workflow", existingBPFInstance.Id);
                                setProcReq.NewProcess         = null;
                            }

                            executeMultipleRequestSetBPF.Requests.Add(setProcReq);

                            recordInstanced++;
                            totalRecordInstanced++;

                            if (recordInstanced % this.settings.NumberOfRecordPerRound == 0 || numberOfRecordsToProceed == recordInstanced)
                            {
                                ExecuteMultipleRequestBPF(user.Id, ref executeMultipleRequestSetBPF, bw,
                                                          recordInstanced, userProceed, "instanced");
                                progress = ((((totalRecordUpdated + totalRecordInstanced) / 2) * 100) / totalRecordToMigrate);
                                SendMessageToStatusBar(this, new StatusBarMessageEventArgs(progress, $"Migration in progress {progress}%  ..."));
                            }
                        }


                        var executeMultipleRequestUpdateBPF = new ExecuteMultipleRequest
                        {
                            Settings = new ExecuteMultipleSettings
                            {
                                ContinueOnError = true,
                                ReturnResponses = true
                            },
                            Requests = new OrganizationRequestCollection()
                        };

                        List <Entity> resultQueryProperBPF = null;
                        //Updating the BPF stage + traversedpath
                        foreach (var record in recordToMigrateList)
                        {
                            if (bw.CancellationPending)
                            {
                                e.Cancel = true;
                                break;
                            }

                            var attrForCondition = bpfSelectedEntityTarget.Contains("_") ? $"bpf_{record.LogicalName}id" : $"{record.LogicalName}id";

                            // So we do it only once
                            if (resultQueryProperBPF == null)
                            {
                                try
                                {
                                    resultQueryProperBPF = this.dm.GetProperBPFList(bpfSelectedEntityTarget,
                                                                                    recordToMigrateList, attrForCondition);
                                }
                                catch (Exception exception)
                                {
                                    if (!continueOnPermissionError)
                                    {
                                        var result = MessageBox.Show(exception.Message, "Error during migration !",
                                                                     MessageBoxButtons.YesNo, MessageBoxIcon.Error);

                                        if (result == DialogResult.No)
                                        {
                                            return;
                                        }
                                        else if (result == DialogResult.Yes)
                                        {
                                            continueOnPermissionError = true;
                                            continue;
                                        }
                                    }
                                    else
                                    {
                                        continue;
                                    }
                                }
                            }

                            var wantedBPFInstanceREcord = resultQueryProperBPF.FirstOrDefault(x => ((EntityReference)x.Attributes[attrForCondition]).Id == record.Id);

                            if (wantedBPFInstanceREcord == null)
                            {
                                //migrationErrors.Add(record);
                                continue;
                            }

                            // Preparing the traversedpath so we do it only once as it's the same path for all records
                            if (traversedpath.Count == 0)
                            {
                                var activePathRequest = new RetrieveActivePathRequest
                                {
                                    ProcessInstanceId = wantedBPFInstanceREcord.Id
                                };
                                var activePathResponse =
                                    (RetrieveActivePathResponse)this.dm.service.Execute(activePathRequest);

                                var stageDefinitions =
                                    ((EntityCollection)activePathResponse.Results.Values.FirstOrDefault())?.Entities;

                                foreach (var path in stageDefinitions)
                                {
                                    traversedpath.Add(path.Id.ToString());

                                    if (path.Attributes["stagename"].ToString() == targetStage)
                                    {
                                        break;
                                    }
                                }
                            }

                            var bpfInstance = new Entity()
                            {
                                LogicalName = wantedBPFInstanceREcord.LogicalName,
                                Id          = wantedBPFInstanceREcord.Id
                            };
                            bpfInstance["activestageid"] = new EntityReference(stageId.LogicalName, stageId.Id);
                            bpfInstance["traversedpath"] = String.Join(",", traversedpath);

                            UpdateRequest ur = new UpdateRequest()
                            {
                                Target = bpfInstance,
                                ConcurrencyBehavior = ConcurrencyBehavior.AlwaysOverwrite
                            };
                            executeMultipleRequestUpdateBPF.Requests.Add(ur);

                            recordUpdated++;
                            totalRecordMigrated++;
                            totalRecordUpdated++;

                            if (totalRecordUpdated % this.settings.NumberOfRecordPerRound == 0 || numberOfRecordsToProceed == recordUpdated)
                            {
                                ExecuteMultipleRequestBPF(user.Id, ref executeMultipleRequestUpdateBPF, bw,
                                                          recordUpdated, userProceed, "updated", false);
                                progress = ((((totalRecordUpdated + totalRecordInstanced) / 2) * 100) / totalRecordToMigrate);
                                SendMessageToStatusBar(this, new StatusBarMessageEventArgs(progress, $"Migration in progress {progress}%  ..."));
                            }

                            Invoke(new Action(() =>
                            {
                                labelRecordsRemaining.Text = $@"{totalRecordToMigrate - totalRecordMigrated}";
                            }));
                        }

                        userProceed++;
                        bw?.ReportProgress(0, $"Processing user {userProceed}/{userList.Count} ...{Environment.NewLine}Total records migrated : {totalRecordMigrated}");
                        SendMessageToStatusBar(this, new StatusBarMessageEventArgs(progress, $"Migration in progress {progress}%  ..."));
                    }

                    e.Result = totalRecordMigrated;
                },
                PostWorkCallBack = e =>
                {
                    if (e.Error != null)
                    {
                        MessageBox.Show(this, e.Error.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                        this.log.LogData(EventType.Exception, LogAction.RecordsMigrated, e.Error);
                        return;
                    }
                    else if (e.Cancelled)
                    {
                        this.log.LogData(EventType.Event, LogAction.MigrationCancelled);
                        MessageBox.Show(
                            $"The migration was successfully cancelled. {Environment.NewLine}{totalRecordMigrated} records were migrated.",
                            "Cancel", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                        labelNumberOfRecordsToMigrate.Text = "The migration will handle : X records.";
                        labelRecordsRemaining.Text         = "X";
                        labelTimeEstimation.Text           = "This can take up to X time.";

                        SendMessageToStatusBar(this, new StatusBarMessageEventArgs(0, "Cancelled ..."));
                    }
                    else
                    {
                        MessageBox.Show($"You migrated {totalRecordMigrated} records !", "Migration done.", MessageBoxButtons.OK, MessageBoxIcon.Information);
                        SendMessageToStatusBar(this, new StatusBarMessageEventArgs("done!."));
                        this.log.LogData(EventType.Event, LogAction.RecordsMigrated);
                    }

                    manageEnablingOfControls(true);
                },
                ProgressChanged = e => { SetWorkingMessage(e.UserState.ToString()); }
            });
        }
Esempio n. 5
0
        public void ChangeStage(IOrganizationService service)
        {
            // Get Process Instances
            var processInstanceRequest = new RetrieveProcessInstancesRequest
            {
                EntityId          = new Guid(IotAlert.Id.ToString()),
                EntityLogicalName = IotAlert.LogicalName.ToString()
            };

            var processInstanceResponse = (RetrieveProcessInstancesResponse)service.Execute(processInstanceRequest);

            // Declare variables to store values returned in response
            Entity activeProcessInstance   = processInstanceResponse.Processes.Entities[0]; // First record is the active process instance
            Guid   activeProcessInstanceID = activeProcessInstance.Id;                      // Id of the active process instance, which will be used later to retrieve the active path of the process instance

            // Retrieve the active stage ID of in the active process instance
            Guid activeStageID = new Guid(activeProcessInstance.Attributes["processstageid"].ToString());

            // Retrieve the process stages in the active path of the current process instance
            RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
            {
                ProcessInstanceId = activeProcessInstanceID
            };
            RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)service.Execute(pathReq);

            var activeStageName     = "";
            var activeStagePosition = -1;

            Console.WriteLine("\nRetrieved stages in the active path of the process instance:");
            for (int i = 0; i < pathResp.ProcessStages.Entities.Count; i++)
            {
                // Retrieve the active stage name and active stage position based on the activeStageId for the process instance
                if (pathResp.ProcessStages.Entities[i].Attributes["processstageid"].ToString() == activeStageID.ToString())
                {
                    activeStageName     = pathResp.ProcessStages.Entities[i].Attributes["stagename"].ToString();
                    activeStagePosition = i;
                }
            }

            // Retrieve the stage ID of the next stage that you want to set as active
            if (activeStagePosition < pathResp.ProcessStages.Entities.Count)
            {
                activeStageID = (Guid)pathResp.ProcessStages.Entities[activeStagePosition + 1].Attributes["processstageid"];
            }
            else
            {
                Console.WriteLine("You are at latest stage");
                return;
            }

            // Retrieve IoT alert Id to match the specific bpf
            var query = new QueryExpression
            {
                EntityName = "msdyn_bpf_477c16f59170487b8b4dc895c5dcd09b",
                ColumnSet  = new ColumnSet("bpf_name", "bpf_msdyn_iotalertid", "activestageid")
            };
            // query.Criteria.AddCondition("processid", ConditionOperator.Equal, activeProcessInstanceID);
            var retrievedProcessInstanceList = service.RetrieveMultiple(query);

            foreach (var entity in retrievedProcessInstanceList.Entities)
            {
                var ioTAlertBpfER = (EntityReference)entity.Attributes["bpf_msdyn_iotalertid"];
                if (IotAlert.Id == ioTAlertBpfER.Id)
                {
                    RetrievedProcessInstance = entity;
                    break;
                }
            }

            //Retrieve Asset's account id
            var customerAsset        = (EntityReference)IotAlert.Attributes["msdyn_customerasset"];;
            var customerAssetIdQuery = new QueryExpression
            {
                EntityName = "msdyn_customerasset",
                ColumnSet  = new ColumnSet("msdyn_account", "msdyn_name", "msdyn_customerassetid"),
                Criteria   = new FilterExpression()
            };

            customerAssetIdQuery.Criteria.AddCondition("msdyn_customerassetid", ConditionOperator.Equal, customerAsset.Id);
            var customerAssetIdCollection = service.RetrieveMultiple(customerAssetIdQuery);

            AccountER = new EntityReference();
            if (customerAssetIdCollection.Entities.Count <= 1)
            {
                //TODO: need to confirm it is account or contact

                AccountER = (EntityReference)customerAssetIdCollection[0].Attributes["msdyn_account"];

                PrimaryAssetER.Id          = customerAssetIdCollection[0].Id;
                PrimaryAssetER.LogicalName = customerAssetIdCollection[0].LogicalName;
                PrimaryAssetER.Name        = customerAssetIdCollection[0].Attributes["msdyn_name"].ToString();
            }
            else
            {
                //more than one value, need developer to do investigation
                return;
            }

            // Retrieve the process instance record to update its active stage
            // activeStagePosition == 0 && activeStageName == "Created"
            CreateCase(service);
            // activeStagePosition == 1 && activeStageName == "Create Work Order"
            CreateWorkOrder(service);
            // activeStagePosition == 2 && activeStageName == "Schedule Work Order"
            ScheduleWorkOrder(service);

            // Set the next stage as the active stage
            // service.Update(RetrievedProcessInstance);
        }
        protected override void Execute(CodeActivityContext executionContext)
        {
            //*** Create the tracing service
            ITracingService tracingService = executionContext.GetExtension <ITracingService>();

            if (tracingService == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve the tracing service.");
            }
            //*** Create the context
            IWorkflowContext context = executionContext.GetExtension <IWorkflowContext>();

            if (context == null)
            {
                throw new InvalidPluginExecutionException("Failed to retrieve the workflow context.");
            }

            tracingService.Trace("{0}.Execute(): ActivityInstanceId: {1}; WorkflowInstanceId: {2}; CorrelationId: {3}; InitiatingUserId: {4} -- Entering", CHILD_CLASS_NAME, executionContext.ActivityInstanceId, executionContext.WorkflowInstanceId, context.CorrelationId, context.InitiatingUserId);

            IOrganizationServiceFactory serviceFactory = executionContext.GetExtension <IOrganizationServiceFactory>();
            IOrganizationService        serviceProxy   = serviceFactory.CreateOrganizationService(context.UserId);

            if (context.InputParameters.Contains(Common.Target) && context.InputParameters[Common.Target] is Entity)
            {
                try {
                    //*** Grab the Target Entity
                    var theEntity = (Entity)context.InputParameters[Common.Target];

                    tracingService.Trace("Active Stage Name: {0}", theEntity.EntityState);
                    //-------------------------------------------------------------------------------------------------------------
                    var processInstancesRequest = new RetrieveProcessInstancesRequest {
                        EntityId          = theEntity.Id,
                        EntityLogicalName = theEntity.LogicalName
                    };

                    var processInstancesResponse = (RetrieveProcessInstancesResponse)serviceProxy.Execute(processInstancesRequest);
                    var processCount             = processInstancesResponse.Processes.Entities.Count;

                    if (processCount > 0)
                    {
                        tracingService.Trace("{0}: Count of Process Instances concurrently associated with the Entity record: {1}", CHILD_CLASS_NAME, processCount);
                        tracingService.Trace("{0}: BPF Definition Name currently set for the Entity record: {1}, Id: {2}", CHILD_CLASS_NAME, processInstancesResponse.Processes.Entities[0].Attributes[CrmEarlyBound.Workflow.Fields.Name], processInstancesResponse.Processes.Entities[0].Id.ToString());

                        var bpfEntityRef = this.BpfEntityReference.Get <EntityReference>(executionContext);
                        var colSet       = new ColumnSet();
                        colSet.AddColumn(CrmEarlyBound.Workflow.Fields.UniqueName);
                        var bpfEntity = serviceProxy.Retrieve(bpfEntityRef.LogicalName, bpfEntityRef.Id, colSet);

                        tracingService.Trace("{0}: Switching to BPF Unique Name: {1}, Id: {2}", CHILD_CLASS_NAME, bpfEntity.Attributes[CrmEarlyBound.Workflow.Fields.UniqueName].ToString(), bpfEntity.Id.ToString());

                        var bpfStageName = this.BpfStageName.Get <string>(executionContext).Trim();
                        var qe           = new QueryExpression {
                            EntityName = CrmEarlyBound.Workflow.EntityLogicalName,
                            ColumnSet  = new ColumnSet(new string[] { CrmEarlyBound.Workflow.Fields.Name }),
                            Criteria   = new FilterExpression {
                                Conditions =
                                {
                                    new ConditionExpression {
                                        AttributeName = CrmEarlyBound.Workflow.Fields.UniqueName, Operator = ConditionOperator.Equal, Values ={ bpfEntity.Attributes[CrmEarlyBound.Workflow.Fields.UniqueName] } //new_bpf_472aceaabf7c4f1db4d13ac3c7076c65
                                    }
                                }
                            },
                            NoLock   = true,
                            Distinct = false
                        };

                        #region Convert Query Expression to FetchXML

                        var conversionRequest = new QueryExpressionToFetchXmlRequest {
                            Query = qe
                        };
                        var conversionResponse = (QueryExpressionToFetchXmlResponse)serviceProxy.Execute(conversionRequest);
                        var fetchXml           = conversionResponse.FetchXml;

                        tracingService.Trace("{0}: [{1}], Message: {2}", CHILD_CLASS_NAME, fetchXml, context.MessageName);

                        #endregion Convert the query expression to FetchXML.

                        tracingService.Trace("{0}: Built BPF Query, Now Executing...", CHILD_CLASS_NAME);

                        var entColByQuery = serviceProxy.RetrieveMultiple(qe).Entities; //// Execute Query with Filter Expressions
                        //-------------------------------------------------------------------------------------------------------------
                        if (entColByQuery != null && entColByQuery.Count > 0)           //// Search and handle related entities
                        {
                            tracingService.Trace("{0}: Found matching Business Process Flows...", CHILD_CLASS_NAME);

                            var bpfId         = new Guid();
                            var bpfEntityName = String.Empty;

                            foreach (var entity in entColByQuery) //// Loop related entities and retrieve Workflow Names
                            {
                                bpfId         = entity.Id;
                                bpfEntityName = entity.GetAttributeValue <string>(CrmEarlyBound.Workflow.Fields.Name);
                                break;
                            }

                            if (bpfId != Guid.Empty)
                            {
                                tracingService.Trace("{0}: Successfully retrieved the Business Process Flow that we'll be switching to: {1}, Id: {2}", CHILD_CLASS_NAME, bpfEntityName, bpfId.ToString());

                                System.Threading.Thread.Sleep(2000); // Wait for 2 seconds before switching the process
                                //*** Set to the new or same Business BpfEntityName Flow
                                var setProcReq = new SetProcessRequest {
                                    Target     = new EntityReference(theEntity.LogicalName, theEntity.Id),
                                    NewProcess = new EntityReference(CrmEarlyBound.Workflow.EntityLogicalName, bpfId)
                                };

                                tracingService.Trace("{0}: ***Ready To Update - Business Process Flow", CHILD_CLASS_NAME);
                                var setProcResp = (SetProcessResponse)serviceProxy.Execute(setProcReq);
                                tracingService.Trace("{0}: ***Updated", CHILD_CLASS_NAME);
                            }
                        }
                        else
                        {
                            tracingService.Trace("{0}: No Business Process Flows were found with Unique Name: {1}", CHILD_CLASS_NAME, bpfEntity.Attributes[CrmEarlyBound.Workflow.Fields.UniqueName].ToString());
                        }
                        //-------------------------------------------------------------------------------------------------------------
                        //*** Verify if the Process Instance was switched successfully for the Entity record
                        processInstancesRequest = new RetrieveProcessInstancesRequest {
                            EntityId          = theEntity.Id,
                            EntityLogicalName = theEntity.LogicalName
                        };

                        processInstancesResponse = (RetrieveProcessInstancesResponse)serviceProxy.Execute(processInstancesRequest);
                        processCount             = processInstancesResponse.Processes.Entities.Count;

                        if (processCount > 0)
                        {
                            var activeProcessInstance   = processInstancesResponse.Processes.Entities[0]; //*** First Entity record is the Active Process Instance
                            var activeProcessInstanceId = activeProcessInstance.Id;                       //*** Active Process Instance Id to be used later for retrieval of the active path of the process instance

                            tracingService.Trace("{0}: Successfully Switched to '{1}' BPF for the Entity Record.", CHILD_CLASS_NAME, activeProcessInstance.Attributes[CrmEarlyBound.Workflow.Fields.Name]);
                            tracingService.Trace("{0}: Count of process instances concurrently associated with the entity record: {1}.", CHILD_CLASS_NAME, processCount);
                            var message = "All process instances associated with the entity record:";

                            for (var i = 0; i < processCount; i++)
                            {
                                message = message + " " + processInstancesResponse.Processes.Entities[i].Attributes[CrmEarlyBound.Workflow.Fields.Name] + ",";
                            }

                            tracingService.Trace("{0}: {1}", CHILD_CLASS_NAME, message.TrimEnd(message[message.Length - 1]));

                            //*** Retrieve the Active Stage ID of the Active Process Instance
                            var activeStageId       = new Guid(activeProcessInstance.Attributes[CrmEarlyBound.ProcessStage.Fields.ProcessStageId].ToString());
                            var activeStagePosition = 0;
                            var newStageId          = new Guid();
                            var newStagePosition    = 0;

                            //*** Retrieve the BPF Stages in the active path of the Active Process Instance
                            var activePathRequest = new RetrieveActivePathRequest {
                                ProcessInstanceId = activeProcessInstanceId
                            };
                            var activePathResponse = (RetrieveActivePathResponse)serviceProxy.Execute(activePathRequest);

                            tracingService.Trace("{0}: Retrieved the BPF Stages in the Active Path of the Process Instance:", CHILD_CLASS_NAME);

                            for (var i = 0; i < activePathResponse.ProcessStages.Entities.Count; i++)
                            {
                                var curStageName = activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.StageName].ToString();

                                tracingService.Trace("{0}: Looping Through Stage #{1}: {2} (StageId: {3}, IndexId: {4})", CHILD_CLASS_NAME, i + 1, curStageName, activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.ProcessStageId], i);
                                //*** Retrieve the Active Stage Name and Stage Position based on a successful match of the activeStageId
                                if (activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.ProcessStageId].Equals(activeStageId))
                                {
                                    activeStagePosition = i;
                                    tracingService.Trace("{0}: Concerning the Process Instance -- Initial Active Stage Name: {1} (StageId: {2})", CHILD_CLASS_NAME, curStageName, activeStageId);
                                }
                                //*** Retrieve the New Stage Id, Stage Name, and Stage Position based on a successful match of the stagename
                                if (curStageName.Equals(bpfStageName, StringComparison.InvariantCultureIgnoreCase))
                                {
                                    newStageId       = new Guid(activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.ProcessStageId].ToString());
                                    newStagePosition = i;
                                    tracingService.Trace("{0}: Concerning the Process Instance -- Desired New Stage Name: {1} (StageId: {2})", CHILD_CLASS_NAME, curStageName, newStageId);
                                }
                            }
                            //-------------------------------------------------------------------------------------------------------------
                            //***Update the Business Process Flow Instance record to the desired Active Stage
                            Entity    retrievedProcessInstance;
                            ColumnSet columnSet;
                            var       stageShift = newStagePosition - activeStagePosition;

                            if (stageShift > 0)
                            {
                                tracingService.Trace("{0}: Number of Stages Shifting Forward: {1}", CHILD_CLASS_NAME, stageShift);
                                //*** Stages only move in 1 direction --> Forward
                                for (var i = activeStagePosition; i <= newStagePosition; i++)
                                {
                                    System.Threading.Thread.Sleep(1000);
                                    //*** Retrieve the Stage Id of the next stage that you want to set as active
                                    var newStageName = activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.StageName].ToString();
                                    newStageId = new Guid(activePathResponse.ProcessStages.Entities[i].Attributes[CrmEarlyBound.ProcessStage.Fields.ProcessStageId].ToString());

                                    tracingService.Trace("{0}: Setting To Stage #{1}: {2} (StageId: {3}, IndexId: {4})", CHILD_CLASS_NAME, i + 1, newStageName, newStageId, i);
                                    //*** Retrieve the BpfEntityName Instance record to update its Active Stage
                                    columnSet = new ColumnSet();
                                    columnSet.AddColumn(ACTIVE_STAGE_ID);
                                    retrievedProcessInstance = serviceProxy.Retrieve(bpfEntity.Attributes[CrmEarlyBound.Workflow.Fields.UniqueName].ToString(), activeProcessInstanceId, columnSet);
                                    //*** Set the next Stage as the Active Stage
                                    retrievedProcessInstance[ACTIVE_STAGE_ID] = new EntityReference(CrmEarlyBound.ProcessStage.EntityLogicalName, newStageId); //(ProcessStage.EntityLogicalName, activeStageId);

                                    try {
                                        tracingService.Trace("{0}: ***Ready To Update -- BPF Stage", CHILD_CLASS_NAME);
                                        serviceProxy.Update(retrievedProcessInstance);
                                        tracingService.Trace("{0}: ***Updated", CHILD_CLASS_NAME);
                                    } catch (FaultException <OrganizationServiceFault> ex) { //*** Determine BPF Stage Requirements
                                        foreach (var stageAttribute in activePathResponse.ProcessStages.Entities[i].Attributes)
                                        {
                                            if (stageAttribute.Key.Equals("clientdata"))
                                            {
                                                tracingService.Trace("{0}: Attribute Key: {1}, Value: {2}", CHILD_CLASS_NAME, stageAttribute.Key, stageAttribute.Value.ToString());
                                                break;
                                            }
                                        }

                                        tracingService.Trace(FullStackTraceException.Create(ex).ToString());
                                        throw;
                                    }
                                }
                            }
                            else
                            {
                                tracingService.Trace("{0}: Number of Stages Shifting Backwards: {1}", CHILD_CLASS_NAME, stageShift);
                            }
                            //-------------------------------------------------------------------------------------------------------------
                            //***Retrieve the Business Process Flow Instance record again to verify its Active Stage information
                            columnSet = new ColumnSet();
                            columnSet.AddColumn(ACTIVE_STAGE_ID);
                            retrievedProcessInstance = serviceProxy.Retrieve(bpfEntity.Attributes[CrmEarlyBound.Workflow.Fields.UniqueName].ToString(), activeProcessInstanceId, columnSet);

                            var activeStageEntityRef = retrievedProcessInstance[ACTIVE_STAGE_ID] as EntityReference;

                            if (activeStageEntityRef != null)
                            {
                                if (activeStageEntityRef.Id.Equals(newStageId))
                                {
                                    tracingService.Trace("{0}: Concerning the Process Instance -- Modified -- Active Stage Name: {1} (StageId: {2})", CHILD_CLASS_NAME, activeStageEntityRef.Name, activeStageEntityRef.Id);
                                }
                            }
                        }
                        else
                        {
                            tracingService.Trace("{0}:The RetrieveProcessInstancesRequest object returned 0", CHILD_CLASS_NAME);
                        }
                    }
                } catch (FaultException <OrganizationServiceFault> ex) {
                    tracingService.Trace("{0}: Fault Exception: An Error Occurred During Workflow Activity Execution", CHILD_CLASS_NAME);
                    tracingService.Trace("{0}: Fault Timestamp: {1}", CHILD_CLASS_NAME, ex.Detail.Timestamp);
                    tracingService.Trace("{0}: Fault Code: {1}", CHILD_CLASS_NAME, ex.Detail.ErrorCode);
                    tracingService.Trace("{0}: Fault Message: {1}", CHILD_CLASS_NAME, ex.Detail.Message);
                    ////localContext.Trace("{0}: Fault Trace: {1}", this.ChildClassName, ex.Detail.TraceText);
                    tracingService.Trace("{0}: Fault Inner Exception: {1}", CHILD_CLASS_NAME, null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault");
                    //*** Display the details of the inner exception.
                    if (ex.InnerException != null)
                    {
                        Exception innerEx = ex;
                        var       i       = 0;
                        while (innerEx.InnerException != null)
                        {
                            innerEx = innerEx.InnerException;
                            tracingService.Trace("{0}: Inner Exception: {1}, Message: {2};", CHILD_CLASS_NAME, i++, innerEx.Message);
                        }
                    }

                    throw new InvalidPluginExecutionException(OperationStatus.Failed, ex.Detail.ErrorCode, ex.Message);
                } catch (Exception ex) {
                    tracingService.Trace("{0}: Exception: An Error Occurred During Workflow Activity Execution", CHILD_CLASS_NAME);
                    tracingService.Trace("{0}: Exception Message: {1}", CHILD_CLASS_NAME, ex.Message);
                    //*** Display the details of the inner exception.
                    if (ex.InnerException != null)
                    {
                        Exception innerEx = ex;
                        var       i       = 0;
                        while (innerEx.InnerException != null)
                        {
                            innerEx = innerEx.InnerException;
                            tracingService.Trace("{0}: Inner Exception: {1}, Message: {2};", CHILD_CLASS_NAME, i++, innerEx.Message);
                        }
                    }

                    throw new InvalidPluginExecutionException(OperationStatus.Failed, ex.HResult, ex.Message);
                } finally {
                    tracingService.Trace("{0}.Execute(): ActivityInstanceId: {1}; WorkflowInstanceId: {2}; CorrelationId: {3} -- Exiting", CHILD_CLASS_NAME, executionContext.ActivityInstanceId, executionContext.WorkflowInstanceId, context.CorrelationId);
                    // Uncomment to force plugin failure for Debugging
                    //--> throw new InvalidPluginExecutionException(String.Format("{0}.Execute(): Plug-in Warning: Manually forcing exception for logging purposes.", CHILD_CLASS_NAME));
                }
            }
        }
Esempio n. 7
0
        /// <summary>
        /// </summary>
        /// <param name="serverConfig">Contains server connection information.</param>
        /// <param name="promptForDelete">When True, the user will be prompted to delete all
        /// created entities.</param>
        public void Run(ServerConnection.Configuration serverConfig, bool promptForDelete)
        {
            try
            {
                // Connect to the Organization service.
                // The using statement assures that the service proxy will be properly disposed.
                using (_serviceProxy = new OrganizationServiceProxy(serverConfig.OrganizationUri, serverConfig.HomeRealmUri, serverConfig.Credentials, serverConfig.DeviceCredentials))
                {
                    // This statement is required to enable early-bound type support.
                    _serviceProxy.EnableProxyTypes();

                    // Creates required records for this sample.
                    CreateRequiredRecords();

                    // Qualify a lead to create an opportunity
                    QualifyLeadRequest qualifyRequest = new QualifyLeadRequest
                    {
                        LeadId            = new EntityReference(Lead.EntityLogicalName, _leadId),
                        Status            = new OptionSetValue((int)lead_statuscode.Qualified),
                        CreateOpportunity = true
                    };
                    QualifyLeadResponse qualifyResponse = (QualifyLeadResponse)_serviceProxy.Execute(qualifyRequest);
                    _opportunityId = qualifyResponse.CreatedEntities[0].Id;
                    if (_opportunityId != Guid.Empty)
                    {
                        Console.WriteLine("\nQualified Lead to create an Opportunity record.");
                    }

                    // Verify the curently active BPF instance for the qualified Opportunity record
                    RetrieveProcessInstancesRequest procOpp1Req = new RetrieveProcessInstancesRequest
                    {
                        EntityId          = _opportunityId,
                        EntityLogicalName = Opportunity.EntityLogicalName
                    };
                    RetrieveProcessInstancesResponse procOpp1Resp = (RetrieveProcessInstancesResponse)_serviceProxy.Execute(procOpp1Req);

                    // Declare variables to store values returned in response
                    Entity activeProcessInstance = null;

                    if (procOpp1Resp.Processes.Entities.Count > 0)
                    {
                        activeProcessInstance = procOpp1Resp.Processes.Entities[0]; // First record is the active process instance
                        _processOpp1Id        = activeProcessInstance.Id;           // Id of the active process instance, which will be used
                                                                                    // later to retrieve the active path of the process instance

                        Console.WriteLine("Current active process instance for the Opportunity record: '{0}'", activeProcessInstance["name"].ToString());
                        _procInstanceLogicalName = activeProcessInstance["name"].ToString().Replace(" ", string.Empty).ToLower();
                    }
                    else
                    {
                        Console.WriteLine("No process instances found for the opportunity record; aborting the sample.");
                        Environment.Exit(1);
                    }

                    // Retrieve the active stage ID of the active process instance
                    _activeStageId = new Guid(activeProcessInstance.Attributes["processstageid"].ToString());

                    // Retrieve the process stages in the active path of the current process instance
                    RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
                    {
                        ProcessInstanceId = _processOpp1Id
                    };
                    RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)_serviceProxy.Execute(pathReq);
                    Console.WriteLine("\nRetrieved stages in the active path of the process instance:");
                    for (int i = 0; i < pathResp.ProcessStages.Entities.Count; i++)
                    {
                        Console.WriteLine("\tStage {0}: {1} (StageId: {2})", i + 1,
                                          pathResp.ProcessStages.Entities[i].Attributes["stagename"], pathResp.ProcessStages.Entities[i].Attributes["processstageid"]);


                        // Retrieve the active stage name and active stage position based on the activeStageId for the process instance
                        if (pathResp.ProcessStages.Entities[i].Attributes["processstageid"].ToString() == _activeStageId.ToString())
                        {
                            _activeStageName     = pathResp.ProcessStages.Entities[i].Attributes["stagename"].ToString();
                            _activeStagePosition = i;
                        }
                    }

                    // Display the active stage name and Id
                    Console.WriteLine("\nActive stage for the process instance: '{0}' (StageID: {1})", _activeStageName, _activeStageId);

                    // Prompt the user to move to the next stage. If user choses to do so:
                    // Set the next stage (_activeStagePosition + 1) as the active stage for the process instance
                    bool moveToNextStage = true;
                    Console.WriteLine("\nDo you want to move to the next stage (y/n):");
                    String answer = Console.ReadLine();
                    moveToNextStage = (answer.StartsWith("y") || answer.StartsWith("Y"));
                    if (moveToNextStage)
                    {
                        // Retrieve the stage ID of the next stage that you want to set as active
                        _activeStageId = (Guid)pathResp.ProcessStages.Entities[_activeStagePosition + 1].Attributes["processstageid"];

                        // Retrieve the process instance record to update its active stage
                        ColumnSet cols1 = new ColumnSet();
                        cols1.AddColumn("activestageid");
                        Entity retrievedProcessInstance = _serviceProxy.Retrieve(_procInstanceLogicalName, _processOpp1Id, cols1);

                        // Update the active stage to the next stage
                        retrievedProcessInstance["activestageid"] = new EntityReference(ProcessStage.EntityLogicalName, _activeStageId);
                        _serviceProxy.Update(retrievedProcessInstance);


                        // Retrieve the process instance record again to verify its active stage information
                        ColumnSet cols2 = new ColumnSet();
                        cols2.AddColumn("activestageid");
                        Entity retrievedProcessInstance1 = _serviceProxy.Retrieve(_procInstanceLogicalName, _processOpp1Id, cols2);

                        EntityReference activeStageInfo = retrievedProcessInstance1["activestageid"] as EntityReference;
                        if (activeStageInfo.Id == _activeStageId)
                        {
                            Console.WriteLine("\nChanged active stage for the process instance to: '{0}' (StageID: {1})",
                                              activeStageInfo.Name, activeStageInfo.Id);
                        }
                    }

                    // Prompts to delete the required records
                    DeleteRequiredRecords(promptForDelete);
                }
            }

            // Catch any service fault exceptions that Microsoft Dynamics 365 throws.
            catch (FaultException <Microsoft.Xrm.Sdk.OrganizationServiceFault> )
            {
                // You can handle an exception here or pass it back to the calling method.
                throw;
            }
        }