/// <summary> /// Creates any entity records that this sample requires. /// </summary> public void CreateRequiredRecords() { // Create a sample Lead record. // This will also create an instance of "Lead To Opportunity Sales Process" // BPF for the new lead record. Lead myLead = new Lead { Subject = "SDK Sample Record", FirstName = "Randy", LastName = "Blythe" }; _leadId = _serviceProxy.Create(myLead); Console.WriteLine("\nCreated a Lead: '{0}'.", myLead.Subject); // Verify that an instance of "Lead To Opportunity Sales Process" is created for the new Lead record. RetrieveProcessInstancesRequest procLeadReq = new RetrieveProcessInstancesRequest { EntityId = _leadId, EntityLogicalName = Lead.EntityLogicalName }; RetrieveProcessInstancesResponse procLeadResp = (RetrieveProcessInstancesResponse)_serviceProxy.Execute(procLeadReq); if (procLeadResp.Processes.Entities.Count > 0) { var processLeadInstance = procLeadResp.Processes.Entities[0]; Console.WriteLine("Process instance automatically created for the new Lead record: '{0}'", processLeadInstance["name"]); } else { Console.WriteLine("No processes found for the Lead record; aborting the sample."); Environment.Exit(1); } }
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); }
static void Main(string[] args) { IOrganizationService organizationService = null; try { ClientCredentials clientCredentials = new ClientCredentials(); clientCredentials.UserName.UserName = "******"; clientCredentials.UserName.Password = "******"; // For Dynamics 365 Customer Engagement V9.X, set Security Protocol as TLS12 ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12; // Get the URL from CRM, Navigate to Settings -> Customizations -> Developer Resources // Copy and Paste Organization Service Endpoint Address URL organizationService = (IOrganizationService) new OrganizationServiceProxy(new Uri("https://hsodevelopment2.api.crm3.dynamics.com/XRMServices/2011/Organization.svc"), null, clientCredentials, null); if (organizationService != null) { Guid userid = ((WhoAmIResponse)organizationService.Execute(new WhoAmIRequest())).UserId; if (userid != Guid.Empty) { Console.WriteLine("Connection Established Successfully..."); } Entity TargetEntity = organizationService.Retrieve("opportunity", Guid.Parse("B76E3BEC-429B-E811-80C2-00155D011409"), new Microsoft.Xrm.Sdk.Query.ColumnSet(true)); var activeInstancesRequest = new RetrieveProcessInstancesRequest { EntityId = TargetEntity.Id, EntityLogicalName = TargetEntity.LogicalName }; Console.WriteLine(TargetEntity.GetAttributeValue <EntityReference>("stageid")); } else { Console.WriteLine("Failed to Established Connection!!!"); } } catch (Exception ex) { Console.WriteLine("Exception caught - " + ex.Message); } Console.ReadKey(); }
public static Entity GetProcessInstanceOfRecord(CrmTestingContext crmContext, EntityReference crmRecord) { if (crmRecord == null) { return(null); } var request = new RetrieveProcessInstancesRequest() { EntityId = crmRecord.Id, EntityLogicalName = crmRecord.LogicalName }; var response = GlobalTestingContext.ConnectionManager.CurrentConnection.Execute <RetrieveProcessInstancesResponse>(request); return(response.Processes.Entities.FirstOrDefault()); }
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); }
protected override void Execute(CodeActivityContext executionContext) { #region "Load CRM Service from context" Common objCommon = new Common(executionContext); objCommon.tracingService.Trace("Load CRM Service from context --- OK"); #endregion #region "Read Parameters" String _ClonningRecordURL = this.ClonningRecordURL.Get(executionContext); if (_ClonningRecordURL == null || _ClonningRecordURL == "") { return; } string[] urlParts = _ClonningRecordURL.Split("?".ToArray()); string[] urlParams = urlParts[1].Split("&".ToCharArray()); string objectTypeCode = urlParams[0].Replace("etc=", ""); string entityName = objCommon.sGetEntityNameFromCode(objectTypeCode, objCommon.service); string objectId = urlParams[1].Replace("id=", ""); objCommon.tracingService.Trace("ObjectTypeCode=" + objectTypeCode + "--ParentId=" + objectId); EntityReference process = this.Process.Get(executionContext); string processStage = this.ProcessStage.Get(executionContext); #endregion #region "SetProcessStage Execution" string stageName = processStage; Guid?stageId = null; if (processStage != null) { objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Process stage: " + stageName); Entity stageReference = new Entity("processstage"); QueryExpression queryStage = new QueryExpression("processstage"); queryStage.ColumnSet = new ColumnSet(); queryStage.Criteria.AddCondition(new ConditionExpression( "stagename", ConditionOperator.Equal, stageName)); queryStage.Criteria.AddCondition(new ConditionExpression( "processid", ConditionOperator.Equal, process.Id)); objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Fetching the requested Stage."); try { stageReference = objCommon.service.RetrieveMultiple(queryStage).Entities.FirstOrDefault(); if (stageReference == null) { throw new InvalidPluginExecutionException( "Process stage " + stageName + " not found"); } stageId = stageReference.Id; } catch (Exception e) { objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Error trying to retrieve " + "the requested stage. Exception: " + e.ToString()); throw new InvalidPluginExecutionException("An error occurred while trying to fetch process stage " + stageName + ". Exception message: " + e.Message + ". Inner Exception: " + e.ToString()); } } //************************* RetrieveProcessInstancesRequest procOpp1Req = new RetrieveProcessInstancesRequest { EntityId = new Guid(objectId), EntityLogicalName = entityName }; RetrieveProcessInstancesResponse procOpp1Resp = (RetrieveProcessInstancesResponse)objCommon.service.Execute(procOpp1Req); // Declare variables to store values returned in response Entity activeProcessInstance = null; Guid _processOpp1Id = Guid.Empty; string _procInstanceLogicalName = ""; 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()); // Get the BPF underlying entity logical name var uniqueProcessNameAttribute = "uniquename"; var processEntity = objCommon.service.Retrieve("workflow", process.Id, new ColumnSet(uniqueProcessNameAttribute)); _procInstanceLogicalName = processEntity.Attributes[uniqueProcessNameAttribute].ToString(); //_procInstanceLogicalName = activeProcessInstance["name"].ToString().Replace(" ", string.Empty).ToLower(); // TO BE REMOVED: Incorrect as it only gets the display name. } else { Console.WriteLine("No process instances found for the opportunity record; aborting the sample."); Environment.Exit(1); } objCommon.tracingService.Trace("Starting the update"); Entity processInstanceToUpdate = new Entity(_procInstanceLogicalName, _processOpp1Id); processInstanceToUpdate.Attributes.Add("activestageid", new EntityReference("processstage", stageId.Value)); objCommon.tracingService.Trace("Starting the update2"); objCommon.service.Update(processInstanceToUpdate); objCommon.tracingService.Trace("Starting the update3"); //************************* /* * // Set the active process and the phase if defined * EntityReference objectReference = new EntityReference(entityName,new Guid(objectId)); * * Entity entityToUpdate = new Entity(); * * if (objectReference != null) * { * entityToUpdate.LogicalName = objectReference.LogicalName; * entityToUpdate.Id = objectReference.Id; * * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Case tu update Id = " + objectReference.Id.ToString() + ", Name = " + objectReference.Name); * } * else * { * entityToUpdate.LogicalName = objCommon.context.PrimaryEntityName; * entityToUpdate.Id = objCommon.context.PrimaryEntityId; * * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Case tu update Id = " + entityToUpdate.Id.ToString()); * } * * entityToUpdate["processid"] = process.Id; * entityToUpdate["stageid"] = stageId.HasValue * ? stageId.Value : default(Guid); * * try * { * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Updating " + * " Case to Update Id = " + entityToUpdate.Id + * " Process Id = " + process.Id + " | Process Name = " + process.Name + * " Stage Id = " + stageId.Value.ToString()); * * objCommon.service.Update(entityToUpdate); * * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Case Id = " + entityToUpdate.Id.ToString() + " updated successfully."); * } * catch (Exception e) * { * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] Error while setting " + * "the active BPF. Details: " + e.ToString()); * throw new InvalidPluginExecutionException("An error occurred while trying to update Business Process to Case Id = " + entityToUpdate.Id.ToString() + * "Exception message " + e.Message + * " Inner exception: " + e.ToString()); * } * objCommon.tracingService.Trace("[Dynamics.ChangeBPFandPhase.Execute] End."); */ #endregion }
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; } }
/// <summary> /// Executes the WorkFlow. /// </summary> /// <param name="crmWorkflowContext">The <see cref="LocalWorkflowContext"/> which contains the /// <param name="executionContext" > <see cref="CodeActivityContext"/> /// </param> /// <remarks> /// For improved performance, Microsoft Dynamics 365 caches WorkFlow instances. /// The WorkFlow's Execute method should be written to be stateless as the constructor /// is not called for every invocation of the WorkFlow. Also, multiple system threads /// could execute the WorkFlow at the same time. All per invocation state information /// is stored in the context. This means that you should not use global variables in WorkFlows. /// </remarks> public override void ExecuteCRMWorkFlowActivity(CodeActivityContext executionContext, LocalWorkflowContext crmWorkflowContext) { if (crmWorkflowContext == null) { throw new ArgumentNullException("crmWorkflowContext"); } var bpfEntityName = this.BpfEntityName.Get <string>(executionContext); if (string.IsNullOrWhiteSpace(bpfEntityName)) { return; } var stageName = this.StageName.Get <string>(executionContext); if (string.IsNullOrWhiteSpace(stageName)) { return; } var tracingService = executionContext.GetExtension <ITracingService>(); var service = crmWorkflowContext.OrganizationService; var ctx = crmWorkflowContext.WorkflowExecutionContext; tracingService.Trace(string.Format("BPF Entity is {0}", bpfEntityName)); tracingService.Trace(string.Format("Primary Entity '{0}' with id={1}", ctx.PrimaryEntityName, ctx.PrimaryEntityId.ToString())); try { // Get the active Business Process Flow Instance var processInstanceReq = new RetrieveProcessInstancesRequest(); processInstanceReq.EntityId = ctx.PrimaryEntityId; processInstanceReq.EntityLogicalName = ctx.PrimaryEntityName; var processInstanceResp = (RetrieveProcessInstancesResponse)service.Execute(processInstanceReq); Entity activeProcessInstance = null; if (processInstanceResp != null && processInstanceResp.Processes.Entities.Count > 0) { // First record is the active process instance activeProcessInstance = processInstanceResp.Processes.Entities[0]; for (int i = 0; i < processInstanceResp.Processes.Entities.Count; i++) { var processInstance = processInstanceResp.Processes.Entities[i]; tracingService.Trace(string.Format("Name={0} id={1}", processInstance.Attributes["name"].ToString(), processInstance.Id.ToString())); } } // Get the active Business Process Stage //var activeStageId = new Guid(activeProcessInstance.Attributes["processstageid"].ToString()); ////var activeProcessName = (string)activeProcessInstance.Attributes["processstageid"]; //tracingService.Trace(string.Format("Got active process instance id={1} with stage id={0}", activeProcessInstance.Attributes["processstageid"].ToString(), activeProcessInstance.Id.ToString())); //// Retrieve the process stages in the active path of the current process instance //var pathReq = new RetrieveActivePathRequest(); //pathReq.ProcessInstanceId = activeProcessInstance.Id; //RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)service.Execute(pathReq); //tracingService.Trace("Retrieved stages in the active path of the process instance:"); //var activeStagePosition = 0; //var activeStageName = string.Empty; //var lastStagePosition = pathResp.ProcessStages.Entities.Count - 1; //for (int i = 0; i < pathResp.ProcessStages.Entities.Count; i++) //{ // tracingService.Trace(string.Format("Stage {0}: {1} (StageId: {2})", (i + 1).ToString(), // pathResp.ProcessStages.Entities[i].Attributes["stagename"].ToString(), // pathResp.ProcessStages.Entities[i].Attributes["processstageid"].ToString())); // // 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 //tracingService.Trace(string.Format("Stage {2} is active for the process instance: {0} (StageID: {1})", activeStageName, activeStageId, (activeStagePosition + 1).ToString())); // if (activeStagePosition == lastStagePosition && direction == "next") // { // tracingService.Trace("Already on last stage. Can't move to next stage."); // } // else if (activeStagePosition == 0 && direction == "previous") // { // tracingService.Trace("Already on first stage. Can't move to first stage."); // } // else // { // Retrieve the stage ID of the next stage that you want to set as active // var nextPosition = activeStagePosition + 1; // if (direction == "previous") // { // nextPosition = activeStagePosition - 1; // } // var nextStageId = (Guid)pathResp.ProcessStages.Entities[nextPosition].Attributes["processstageid"]; // tracingService.Trace(string.Format("Stage {0} is next with id={1}", (nextPosition + 1).ToString(), nextStageId.ToString())); var processName = activeProcessInstance.Attributes["name"].ToString(); var fetchXml = string.Format(@"<fetch top='1' > <entity name='workflow' > <attribute name='workflowid' /> <filter> <condition attribute='name' operator='eq' value='{0}' /> <condition attribute='statecode' operator='eq' value='1' /> </filter> <link-entity name='processstage' from='processid' to='workflowid' alias='stage' > <attribute name='processstageid' /> <filter type='and' > <condition attribute='stagename' operator='eq' value='{1}' /> </filter> </link-entity> </entity> </fetch>", processName, stageName); tracingService.Trace(fetchXml); var process = Query.QueryCRMForSingleEntity(service, fetchXml); if (process == null) { throw new InvalidPluginExecutionException(string.Format("Process {0} or Stage {1} does not exist", processName, stageName)); } var nextStageId = (Guid)(process.GetAttributeValue <AliasedValue>("stage.processstageid")).Value; // Retrieve the process instance record to update its active stage var cols1 = new ColumnSet(); cols1.AddColumn("activestageid"); var retrievedProcessInstance = service.Retrieve(bpfEntityName, activeProcessInstance.Id, cols1); // tracingService.Trace(string.Format("Active Stage Id is a lookup to {0}", pathResp.ProcessStages.Entities[nextPosition].LogicalName)); // Set the next stage as the active stage retrievedProcessInstance["activestageid"] = new EntityReference(bpfEntityName, nextStageId); service.Update(retrievedProcessInstance); // } } catch (Exception ex) { tracingService.Trace(string.Format("ERROR. Move Next Stage Activity: {0} {1}", ex.Message, ex.StackTrace)); throw new InvalidPluginExecutionException("An error occured while moving to next stage. Please ask an administrator for further actions."); } }