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()); }
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()); } }); }
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)); } } }
/// <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; } }