Fulfilment Workflow Lab
Objective
Create a fulfillment workflow that adds accounts to a group.
Complete this lab Creating and Understanding the Fulfillment Workflow - EmpowerID Certifications - Confluence before starting or at least review it to help avoid potential issues. The previous lab provides detailed explanations.
Login to Workflow Studio
Go to your Demo folder or any folder you have created containing sub folders Workflows>Application
Right-click on the Application folder in the Workflow Studio and select New Workflow > Fulfillment Workflow from the context menu to create a new fulfillment workflow.
Save the workflow by clicking on the Save icon in the toolbar and provide a suitable name for the fulfillment workflow. Once you save, the workflow will reload and show you the default activities.
We will perform the Add Accounts to Group operation using the default operation base activity available in EmpowerID. To find the necessary activity, go to the Activities pane or you can also find the activity by going the Search tab, enter the relevant search text, and select the AddAccountsToGroupsOperation from the search results. Afterward, drag and drop the activity to the "Drag Operation Activities Hereā placeholder. Click on the newly added operation activity and provide a suitable name and description. In the Name field, enter āAddAccountToGroup,' and in the Description text box, enter 'Add Account To Groupā.
Ā
Enable the operation on the Operation Base Activity.
Create a property by going to the Properties tab and naming it BriGroupAccountDictionary.
Ā
Now, double-click the SetOperationInputs activity, or right-click on the activity and select the first option, Edit SetOperationInputs_ExecuteCode. This will open the code editor window.
Click the Visual Studio icon in the top bar to open the workflow or solution in Visual Studio.
Before making changes to the workflow in Visual Studio, first save and close the workflow window in Workflow Studio.
Ā
Return to Visual Studio. You may see a File Modification Detected popup. Click the Reload All button.
In Solution Explorer, double-click SetOperationInputs_ExecuteCode.cs and scroll down to the Implement method. Write the below code in the Implement method.
// Initialize a list to hold target group accounts that need to be added.
E.TList<C.GroupAccount> targetGroupAccounts = new E.TList<GroupAccount>();
// Extract distinct Assignee GUIDs from the claimed business request items.
var acGuids = CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems
.Select(bri => bri.RequestDataAssigneeID) // Select the Assignee IDs
.Where(guid => guid.HasValue) // Ensure the GUID is not null
.Select(guid => guid.Value) // Extract the GUID value
.Distinct() // Remove duplicates
.ToList(); // Convert to a list
// Extract distinct Target Resource GUIDs from the claimed business request items.
var grGuids = CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems
.Select(bri => bri.RequestDataTargetResourceID) // Select the Target Resource IDs
.Where(guid => guid.HasValue) // Ensure the GUID is not null
.Select(guid => guid.Value) // Extract the GUID value
.Distinct() // Remove duplicates
.ToList(); // Convert to a list
// Retrieve Account objects based on the extracted Assignee GUIDs.
var targetAccounts = C.Account.GetByAccountGuids(acGuids);
// Create a dictionary for quick lookup of Account objects by their GUID.
Dictionary<Guid, C.Account> accountDictionary = targetAccounts
.ToList()
.ToDictionary(a => a.AccountGUID, a => a);
// Retrieve Group objects based on the extracted Target Resource GUIDs.
var targetGroups = C.Group.GetByGroupGUIDs(grGuids);
// Create a dictionary for quick lookup of Group objects by their GUID.
Dictionary<Guid, C.Group> groupDictionary = targetGroups
.ToList()
.ToDictionary(a => a.GroupGUID, a => a);
// Retrieve existing GroupAccount associations based on the current business request items.
var existingGroupAccount = C.GroupAccount.GetByBusinessRequestItemList(
CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems.ToXml().ToString()
);
// Initialize a dictionary to map a composite key to its corresponding BusinessRequestItem.
CurrentWorkflow.BriGroupAccountDictionary = new Dictionary<string, C.BusinessRequestItem>();
// Iterate through each claimed business request item to process group-account associations.
foreach (var bri in CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems)
{
// Create a unique key combining Assignee ID and Target Resource ID.
var key = string.Format("{0}_{1}", bri.RequestDataAssigneeID.Value, bri.RequestDataTargetResourceID.Value);
// Map the unique key to the current BusinessRequestItem.
CurrentWorkflow.BriGroupAccountDictionary[key] = bri;
// Retrieve the AccountID using the Assignee GUID from the account dictionary.
int acID = accountDictionary[bri.RequestDataAssigneeID.Value].AccountID;
// Retrieve the GroupID using the Target Resource GUID from the group dictionary.
int grID = groupDictionary[bri.RequestDataTargetResourceID.Value].GroupID;
// Create a new GroupAccount instance with the retrieved AccountID and GroupID.
var ga = new C.GroupAccount()
{
AccountID = acID,
GroupID = grID
};
// Check if the GroupAccount already exists to avoid duplicates.
bool groupAccountExists = existingGroupAccount
.Any(a => a.AccountID == acID && a.GroupID == grID);
if (groupAccountExists)
{
// If the GroupAccount exists, update the BusinessRequestItem's process status to indicate duplication.
bri.ProcessStatus = 4; // TODO: Replace magic number with an enum for better readability.
bri.BusinessRequestItemFulfillmentStatusID = 3;
}
else
{
// If the GroupAccount does not exist, add it to the list of target group accounts to be added.
targetGroupAccounts.Add(ga);
}
}
// Assign the list of new GroupAccounts to the workflow's AddAccountToGroup target.
CurrentWorkflow.AddAccountToGroup.TargetGroupAccounts = targetGroupAccounts;
// Initialize a dictionary to map Target Resource GUIDs to their corresponding BusinessRequestItems.
CurrentWorkflow.BusinessRequestItemDictionary = new Dictionary<Guid, BusinessRequestItem>();
// Populate the BusinessRequestItemDictionary with entries from the claimed business request items.
foreach (var bri in CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems)
{
// Map the Target Resource GUID to the corresponding BusinessRequestItem.
// Note: This assumes that each Target Resource GUID is unique. If not, consider using a list.
CurrentWorkflow.BusinessRequestItemDictionary[bri.RequestDataTargetResourceID.Value] = bri;
}
In Solution Explorer, open the SetBusinessRequestItemStatus_ExecuteCode.cs file. If you see red wiggly lines, it means it is pointing to the wrong workflow, so you need to replace it with your workflow name.
The code in SetBusinessRequestItemStatus_ExecuteCode.cs file is executed after your Operation Base Activity.
Add the following code to the Implement method in the SetBusinessRequestItemStatus_ExecuteCode.cs file.
// TODO: Implementation goes here!
// Initialize a list to hold the results of operation executions.
List<Framework.Common.Shared.Workflow.OperationExecutionSummary> oplist = new List<Framework.Common.Shared.Workflow.OperationExecutionSummary>();
// Iterate through each operation execution summary in the operation list.
foreach (Framework.Common.Shared.Workflow.OperationExecutionSummary op in oplist)
{
// NOTE: To retrieve a new Business Request, a new dictionary is needed.
// Create a unique key by combining the LeftResourceGUID and RightResourceGUID.
string key = string.Format("{0},{1}", op.LeftResourceGUID, op.RightResourceGUID);
// Retrieve the corresponding BusinessRequestItem from the BriGroupAccountDictionary using the generated key.
C.BusinessRequestItem bri = CurrentWorkflow.BriGroupAccountDictionary[key];
// Update the process status of the BusinessRequestItem to '2' indicating it is being processed.
bri.ProcessStatus = 2;
// Check if the operation was executed successfully.
if (op.OperationExecuted)
{
// If the operation succeeded, set the fulfillment status to '3' indicating success.
bri.BusinessRequestItemFulfillmentStatusID = 3; // Success
}
else
{
// If the operation failed, set the fulfillment status to '4' indicating failure.
bri.BusinessRequestItemFulfillmentStatusID = 4; // Fail
// Update the process status to '3' indicating an error occurred during processing.
bri.ProcessStatus = 3;
// Increment the failed attempt count for this BusinessRequestItem.
bri.FailedCount += 1;
// Record the timestamp of the last failure.
bri.LastFailed = DateTime.UtcNow;
// Schedule the next attempt based on the number of failed attempts (exponential backoff).
bri.NextAttempt = DateTime.UtcNow.AddMinutes(10 * bri.FailedCount * bri.FailedCount);
// Store the error message returned from the operation execution.
bri.LastFailedError = op.ExecutionResultMessage;
}
}
// Create a list of all BusinessRequestItems from the BriGroupAccountDictionary.
var bris = new E.TList<C.BusinessRequestItem>(
CurrentWorkflow.BriGroupAccountDictionary.Select(a => a.Value).ToList()
);
// Persist the updated BusinessRequestItems to the database.
BusinessRequestItem.Update(bris);
Compile and Publish the Workflow
We compile and publish the Fulfillment Workflow in Workflow Studio the same way we publish our UI workflows. Once published from Workflow Studio, we also publish them through the EmpowerID Web UI.
Ā
The following is not the recommended way to retrieve accounts and groups from the database.
E.TList<C.GroupAccount> targetgroupAccount = new E.TList<GroupAccount>();
foreach (var bri in CurrentWorkflow.ValidateBRIs.ClaimedBusinessRequestItems)
{
var ac = C.Account.GetByAccountGUID(bri.RequestDataAssigneeID.Value);
var gr = C.Group.GetByGroupGUID(bri.RequestDataTargetResourceID.Value);
var ga = new C.GroupAccount() { AccountID = ac.AccountID, GroupID = gr.GroupID };
targetgroupAccount.Add(ga);
}
Ā