Thursday, May 31, 2018

D365/AX7 – Add validation before workflow approval action

This blog will provide you a solution to add validation before the user performs any approval action on the assigned workflow task


Problem

To add validation before the user performs any approval action on the workflow item.


Solution

Add custom workflow work item action manager class.

Step#1 Add a new class extending the class WorkflowWorkItemActionManager

class MY_TaskWorkflowActionManager extends WorkflowWorkItemActionManager
{

}


Step#2 Add the code below to the class

public static void main(Args _args)
{
MY_TaskWorkflowActionManager taskWorkflowActionManager = new MY_TaskWorkflowActionManager();
       
taskWorkflowActionManager.parmCaller(_args.caller());

if(_args.record() && _args.record().TableId == tableNum(MY_TaskTable))
{
if(taskWorkflowActionManager.validate())
{
       taskWorkflowActionManager.parmArgs(_args);
taskWorkflowActionManager.run();
}
       else
       {
              throw error("Task must be valid to perform the action");
       }
}
else
       {
              throw error("Invalid action requested");
}
}

public boolean validate()
{
boolean ret;

       //Add your validation here...

       return ret;

}


Step#3 Go to the action menu item of the above modified outcome and set the property Object with your custom workflow action manager class name




And that’s it. You can similarly use this action manager class for other outcomes of your workflow approval too.

D365/AX7 – How to apply workflow hierarchy type at runtime

The default workflow hierarchy providers as provided by Microsoft Dynamics AX, allow us to use managerial or configurable hierarchy as setup for the workflow. However, when comes a requirement where the hierarchy type of the workflow should be decided at run time, we need to do some customizations with workflow hierarchy providers.


Problem


To select workflow hierarchy type for each record at run time. 







Here, we need the workflow to be approved by the Task hierarchy of the workflow originator (say Aaliyah). The Task hierarchy of the worker Aaliyah is as follows.




Solution


To achieve above requirement, follow the steps below to create custom workflow hierarchy provider for any specified hierarchy type.

Step#1 In order to add a custom workflow hierarchy provider, refer the blog How to add custom workflow hierarchy assignment provider

Step#2 Add a method to get the position hierarchy type from the record the workflow is executing for.

public HcmPositionHierarchyTypeRecId getPositionHierarchyType(
WorkflowContext _workflowContext)
{
MY_TaskTable                 taskTable;

if(_workflowContext.parmTableId() == tableNum(MY_TaskTable))
{
taskTable = MY_TaskTable::find(_workflowContext.parmRecId());
}

return taskTable.PositionHierarchyType;

}

Step#3 Modify the method getNextNode as below

public WorkflowHierarchyProviderNode getNextNode(anytype _nodeId,
WorkflowHierarchyLevel _level,
WorkflowContext _workflowContext)
{
HcmPositionHierarchyTypeRecId positionHierarchyTypeRecId = this.getPositionHierarchyType(_workflowContext);
       
if (positionHierarchyTypeRecId == 0)
{
throw error("Position hierarchy not defined for the workflow");
}

return helper.getNextNode(_nodeId, _level, _workflowContext, dataSource, positionHierarchyTypeRecId);
}

Step#4 Build the relevant model.

Execution


Setup the workflow using task workflow hierarchy provider.


According to the task hierarchy of the worker Aaliya (workflow originator), and the workflow design as above, the task will be first assigned to Adam and then to Julia for approval. 


D365/AX7 – How to add hierarchy token using custom workflow hierarchy provider

Workflow hierarchy assignment usually provides limited options to select the start of the given hierarchy. Most common options to select for the start of hierarchy are Workflow owner, Workflow originator, Personnel number, User etc. E.g. the workflow is assigned to the managerial hierarchy of the workflow originator.


Problem

To add hierarchy token using custom workflow hierarchy provider, so that we have option to select the start of hierarchy other than those already provided by the default provider.


Solution

To achieve above requirement, follow the steps below to create custom workflow hierarchy provider and add the token using it.

Step#1 In order to add a custom workflow hierarchy provider, refer the blog How to add custom workflow hierarchy assignment provider

Step#2 Add new EDT which extends HcmWorkerRecId


Step#3 Assign the EDT to the table field, which you want to be the starting point for workflow managerial hierarchy.



Step#4 Implement the method getSupportedType of custom workflow hierarchy provider class to add your data type i.e. MY_SupervisorWorkerRecId

public Set getSupportedDataType()
{
Set supportedDataTypes = helper.getSupportedDataType();

if(!supportedDataTypes)
{
supportedDataTypes = new Set(Types::String);
}

//Add the required data types
supportedDataTypes.add(extendedTypeStr(MY_SupervisorWorkerRecId));
return supportedDataTypes;

}

Step#5 Implement the method convertToNodeDataType of custom workflow hierarchy provider class to fetch the worker’s personnel number using the field value from the record (workflow document).

public anytype convertToNodeDataType(extendedDataTypeName _dataType,
anytype _value,
       WorkflowContext _workflowContext)
{
HcmPersonnelNumberId personnelNumberId;

if(_dataType == extendedTypeStr(MY_SupervisorWorkerRecId))
{
personnelNumberId = HcmWorker::find(_value).PersonnelNumber;
}
else
{
personnelNumberId = helper.convertToNodeDataType(_dataType, _value, _workflowContext);
}
return personnelNumberId;

}

Step#6 Build the relevant model.

Execution

Setup workflow using custom hierarchy token for supervisor


A task to submit workflow by Admin. We need the workflow approval from line manager of the supervisor here i.e. Aaliyah.




Workflow is assigned to the line manager of Aaliya i.e. Adam Carter, as specified in the workflow designer

D365/AX7 – How to create custom workflow hierarchy assignment provider

The workflow designer provides a variety of configuration options to setup workflow as per our business needs. Workflow providers are the key components of the workflows in Microsoft Dynamics AX. These can be used to provide application specific information to the workflow instance at runtime.
You can go through the Workflow Providers Overview for brief introduction related to workflow providers in Microsoft dynamics AX.
We are going to look into the application of workflow hierarchy provider in order to solve the problem below.


Problem

To create a custom workflow hierarchy provider

Solution

Create custom workflow hierarchy provider using workflow hierarchy helper class for default behavior.

Step#1 Add new class for custom workflow hierarchy provider and implement with WorkflowHierarchyProvider class.

class MY_TaskWorkflowHierarchyProvider implements WorkflowHierarchyProvider
{
    const str Workflow_Employee = 'Employee';

    ExpressionDataSource            dataSource;
    WorkflowHierarchyProviderHelper helper;
}

Step#2 Override new method of the provider class as below

protected void new()
{
       helper = WorkflowHierarchyProviderHelper::construct();
dataSource = ExpressionDataSource::newDataSourceDefinition(Workflow_Employee, "@SYS121302");
       helper.setupDataSource(dataSource);
}

public static MY_TaskWorkflowHierarchyProvider construct()
{
       return new MY_TaskWorkflowHierarchyProvider();
}

Step#3 Implement the methods below with the default implementation of the workflow hierarchy provider using WorkflowHierarchyProviderHelper class

public anytype convertUserIdToNodeDataType(userId _userId,
WorkflowContext _workflowContext)
{
return helper.convertUserIdToNodeDataType(_userId, _workflowContext);
}

public ExpressionDataSource getDataSource()
{
return dataSource;
}

public WorkflowHierarchyProviderNode getNextNode(anytype _nodeId,
WorkflowHierarchyLevel _level,
WorkflowContext _workflowContext)
{
return helper.getNextNode(_nodeId, _level, _workflowContext, dataSource);
}

public extendedDataTypeName getNodeDataType()
{
return helper.getNodeDataType();
}

public Set getSupportedDataType()
{
return helper.getSupportedDataType();
}

public anytype convertToNodeDataType(extendedDataTypeName _dataType,
anytype _value,
       WorkflowContext _workflowContext)
{
return helper.convertToNodeDataType(_dataType, _value, _workflowContext);
}


Step#4 Add new workflow hierarchy assignment provider and set the Provider Class property with your custom hierarchy provider class name.





If the property Available for All Workflows is set to Yes, the provider will be applied to all the workflow types.
You can add your workflow type to enable this provider for the selective workflow and set the property Available for All Workflows to No.

Step#5 Build the relevant model.


Execution

Setup the workflow using task workflow hierarchy provider.


You can now add your customizations related to workflow hierarchy in this class.


Wednesday, May 30, 2018

D365/AX7 – How to add expression field for workflow hierarchy assignment


We have several scenarios when we need to have option to select additional field for hierarchy stopping condition and expression to exclude users when setting up the workflow design. Let’s have a look at how we can add field for hierarchy assignment expression for workflow.


Problem

To add field for hierarchy assignment conditions i.e. stopping condition and the condition to exclude users.
Consider a scenario where we need to assign workflow to an employee’s line managerial hierarchy. We need to add condition to exclude the workers (users) from the hierarchy, who does not belong to the department 022.

Solution

Following steps need to be performed to achieve the above requirement.
Step#1 Add new class to put all the relevant event handlers

class TaskWorkflowHierarchyProviderHandler
{
    const str Workflow_DepartmentId = 'DepartmentId';       

}

Step#2 Copy following event handlers from the class WorkflowHierarchyProviderHelper to your event handler class
1.       addAdditionalFieldsToDataSourceDelegate
2.       addDataSourceFieldsDelegate

Step#3 Add the below code to the method addAdditionalFieldsToDataSourceDelegate


/// <summary>
/// Add fields to data source
/// </summary>
/// <param name="_datasource">Expression data source</param>
[SubscribesTo(classStr(WorkflowHierarchyProviderHelper), delegateStr(WorkflowHierarchyProviderHelper, addAdditionalFieldsToDataSourceDelegate))]
public static void addAdditionalFieldsToDataSourceDelegate(ExpressionDataSource _datasource)
{
      _datasource.addField(ExpressionField::newFieldDefinition(Workflow_DepartmentId, extendedTypeStr(OMOperatingUnitNumber), "Department Id"));

}

Step#4 Add the below code to the method addDataSourceFieldsDelegate

/// <summary>
/// Add fields with values to the node data source
/// </summary>
/// <param name="_nodeDataSource">Node data source</param>
/// <param name="_workflowContext">Workflow context</param>
/// <param name="_hcmWorker">Worker at node</param>
/// <param name="_positionRecId">Positon of worker </param>
[SubscribesTo(classStr(WorkflowHierarchyProviderHelper), delegateStr(WorkflowHierarchyProviderHelper, addDataSourceFieldsDelegate))]
public static void addDataSourceFieldsDelegate(ExpressionDataSource _nodeDataSource,
WorkflowContext _workflowContext,
HcmWorker _hcmWorker,
HcmPositionRecId _positionRecId)
{
        HcmPositionDetail   postionDetail = HcmPositionDetail::findByPosition(_positionRecId);
        OMOperatingUnit     department = OMOperatingUnit::find(postionDetail.Department, OMOperatingUnitType::OMDepartment);
       
        _nodeDataSource.addField(ExpressionField::newFieldValue(Workflow_DepartmentId, extendedTypeStr(OMOperatingUnitNumber), department.OMOperatingUnitNumber));

}

This method sets the value for department Id for each worker in hierarchy.

Step#5 Build the respective model

Execution

Workflow will be assigned to the managerial hierarchy of supervisor Aaliyah. Set manager level to 2, so we have the hierarchy including Adam and Julia.


Add condition to exclude users who does not belong to department 022

Submit the workflow to verify the workflow assignment. The workflow assignment exclude the worker Adam, as he does not belong to the department 022, and thus directly assigns to Julia.