Bhubaneswar, Odisha, India
+91-8328865778
support@softchief.com

Automate BPF Stage Selection using Server Side Code Plugins with Related Entity Parent Child Scenario

Automate BPF Stage Selection using Server Side Code Plugins with Related Entity Parent Child Scenario

In this Post, you will come to know how to Automatically Set the Active Stage and Move the stages automatically as per child record field update.

Business Requirement

There is a business use case, which tells that, there are two table Teacher (1) and Classes (N) . Every time a Teacher is created in the system, user can create two child class records. One class is Regular Class and another is Extra class (As screenshot given below). The automation requirement is, There should be a BPF which will have 4 stages such as STAGE 1: Teacher Name, STAGE 2: Regular Class Status, STAGE 3: Extra Class Status, STAGE 4 : Teacher Mobile Info.

When a user marks a child class record of type Regular, the BPF stage must automatically complete the STAGE 2 (Regular Class Status), Updates Regular Class Status Column field as Completed and activate STAGE 3 (Extra Class Status).

When a user marks a child class record of type Extra, the BPF stage must automatically complete the STAGE 3 (Extra Class Status), Updates Extra Class Status Column field as Completed and activate STAGE 4 (Teacher Mobile Info).

Pre-requisites

  • Create 2 tables, One table is Teacher with columns name and mobile number. Second Table is Class with columns such as Name, Type (Regular/Extra) Choice Column, Teacher Lookup
  • The Teacher lookup column in Class table will automatically create a (Teacher(One)- Class(Many)) relationship.
  • Design Forms and Views to add Custom Columns.
  • Add a Classes Sub-grid on Teacher Table main form.

STEP 1 : Design Forms for the App

The below screenshot shows Teacher table Form

The below screenshot is for Class Form.

STEP 2 : Configure BPF

Now Configure a Business Process Flow for the Parent entity Teacher with 4 stages. Each stage connect to different columns of the same table.

Take two new columns in Teacher table to store Regular Class record Status value and Extra class record status value.

Activate the BPF.

STEP 3 : Develop Plugin to Trigger on Child Record (Class Table)

Now you have to develop a plugin to achieve the automation. Use the below Plugin code for this.

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

namespace HSBC_Plugins
{
    public class AutomateBPFStageSelection_Classtype : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // your custom code goes here
            IPluginExecutionContext context = (IPluginExecutionContext)
                        serviceProvider.GetService(typeof(IPluginExecutionContext));

            IOrganizationServiceFactory serviceFactory =
                     (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

            IOrganizationService orgService = serviceFactory.CreateOrganizationService(context.UserId);

            ITracingService tracingService =
                (ITracingService)serviceProvider.GetService(typeof(ITracingService));
            try
            {
                string logicalNameOfBPF = "hsbc_classbpf";
                string parentEntiyLogicalname = "hsbc_teacher";

                if (context.MessageName.ToLower().Equals("update") && context.PrimaryEntityName.ToLower().Equals("hsbc_class"))
                {
                    if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
                    {
                        Entity entity = (Entity)context.InputParameters["Target"];
                        EntityReference parentEntityTeacherLookup = context.PreEntityImages["preimage"].GetAttributeValue<EntityReference>("hsbc_teacher");
                        Entity teacherEntity = orgService.Retrieve(parentEntiyLogicalname, parentEntityTeacherLookup.Id, new Microsoft.Xrm.Sdk.Query.ColumnSet("hsbc_name"));

                        int classtype = context.PreEntityImages["preimage"].GetAttributeValue<OptionSetValue>("hsbc_type").Value;
                        //768280000 = Extra , 768280001= Regular

                        if (entity.Contains("statuscode") && entity["statuscode"] != null)
                        {
                            //This code works if you have only one BPF for the entity
                            Entity activeBPFProcessInstance = GetActiveBPF(teacherEntity, orgService);
                            if (activeBPFProcessInstance != null)
                            {
                                // Id of the active process instance, which will be used
                                Guid activeBPFId = activeBPFProcessInstance.Id;

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

                                int currentStagePosition = -1;
                                RetrieveActivePathResponse pathResp = GetAllStagesOfSelectedBPF(activeBPFId, activeStageId, ref currentStagePosition, orgService);
                                if (currentStagePosition > -1 && pathResp.ProcessStages != null && pathResp.ProcessStages.Entities != null && currentStagePosition + 1 < pathResp.ProcessStages.Entities.Count)
                                {
                                    // Retrieve the stage ID of the next stage that you want to set as active
                                    Guid nextStageId = Guid.Empty;
                                    if (classtype == 768280001)//regular
                                    {
                                        nextStageId = (Guid)pathResp.ProcessStages.Entities[currentStagePosition + 2].Attributes["processstageid"];
                                        Entity entityTeach = new Entity("hsbc_teacher");
                                        entityTeach.Id = parentEntityTeacherLookup.Id;
                                        entityTeach["hsbc_regularclassstatus"] = new OptionSetValue(768280000);//Completed
                                         orgService.Update(entityTeach);
                                    }
                                    else if (classtype == 768280000) //extra
                                    {
                                        nextStageId = (Guid)pathResp.ProcessStages.Entities[currentStagePosition + 1].Attributes["processstageid"];
                                        Entity entityTeach = new Entity("hsbc_teacher");
                                        entityTeach.Id = parentEntityTeacherLookup.Id;
                                        entityTeach["hsbc_extraclassstatus"] = new OptionSetValue(768280000);//Completed
                                        orgService.Update(entityTeach);
                                    }
                                    // Set the next stage as the active stage
                                    Entity entBPF = new Entity(logicalNameOfBPF)
                                    {
                                        Id = activeBPFId
                                    };
                                    entBPF["activestageid"] = new EntityReference("processstage", nextStageId);

                                    orgService.Update(entBPF);
                                }
                            }

                        }
                    }
                }
            }
            catch (InvalidPluginExecutionException ex)
            {
                throw ex;
            }
        }

        public Entity GetActiveBPF(Entity entity, IOrganizationService crmService)

        {
            Entity activeProcessInstance = null;

            RetrieveProcessInstancesRequest entityBPFsRequest = new RetrieveProcessInstancesRequest
            {
                EntityId = entity.Id,
                EntityLogicalName = entity.LogicalName
            };

            RetrieveProcessInstancesResponse entityBPFsResponse =
                (RetrieveProcessInstancesResponse)crmService.Execute(entityBPFsRequest);

            // Declare variables to store values returned in response
            if (entityBPFsResponse.Processes != null && entityBPFsResponse.Processes.Entities != null)
            {
                int processCount = entityBPFsResponse.Processes.Entities.Count;
                activeProcessInstance = entityBPFsResponse.Processes.Entities[0];
            }
            return activeProcessInstance;
        }

        public RetrieveActivePathResponse GetAllStagesOfSelectedBPF(Guid activeBPFId, Guid activeStageId,
            ref int currentStagePosition, IOrganizationService crmService)
        {
            // Retrieve the process stages in the active path of the current process instance
            RetrieveActivePathRequest pathReq = new RetrieveActivePathRequest
            {
                ProcessInstanceId = activeBPFId
            };
            RetrieveActivePathResponse pathResp = (RetrieveActivePathResponse)crmService.Execute(pathReq);
            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())
                {
                    currentStagePosition = i;
                }
            }
            return pathResp;
        }
    }
}

STEP 4 : REGISTER THE PLUGIN

Register the plugin on Parent table Update Messge

TEST RESULT

Now once you test you can get below result.

Create a Teacher and create two child records of class using the sub-grid one Regular type and other is Extra type. below is the screenshot. You will observe here that, the BPF on top showing First Stage Active.

Now Select Regular type class record and Complete It and once done , Click Refresh Command on top command bar of the form. You will see the result in below screenshot.

  1. Type is Extra
  2. Status changed to Completed
  3. Stage 1 and Stage 2 completes
  4. Stage 3 is activated.

Now Select the Extra Class record and mark it as completed then you will see Extra stage will also be completed automatically and the status values also updated.

That is all.

Hope this helps.

You can watch the video in my YouTube channel