AX 2012: Create Custom Workflow

Purpose:

The purpose of this document is to describe how we can develop a custom workflow template.

Business requirement:

Ability to have approval process for customers. Standard AX does not offer any workflow for customers approval out-of-the-box.

Unit testing prerequisites:

The following steps must be completed before a workflow can be unit tested.

  1. Configure workflow execution account.
  2. Configure workflow batch jobs

Development:

1. Create a workflow status Enum to have the following elements:

customer-approval-workflow

2. Add field of type workflow status enum to the CustTable table.
3. Override canSubmitToWorkflow() method of CustTable table to define workflow submission criteria.

public boolean canSubmitToWorkflow(str _workflowType = '')
{
    boolean canSubmit = false;

    if (custTable.RecId &&
	custTable.MzkWorkflowApprovalStatus == MzkCustWFApprovalStatus::NotSubmitted)
    {
        canSubmit = true;
    }

    return canSubmit;
}

4. Add a static method on CustTable table to update workflow status. This method will be called from workflow event handlers and workflow approval event handlers.

static void mzkUpdateWorkflowStatus(RefRecId _recId, MzkCustWorkflowStatus _status)
{
    CustTable custTable;

    custTable = CustTable::findRecId(_recId, true);

    ttsBegin;
    custTable.MzkWorkflowApprovalStatus = _status;
    custTable.update();
    ttsCommit;
}

5. Create a Query for the CustTable table.

customer-approval-workflow

6. Create a Workflow Category.
7. Create a Workflow Type using wizard.

customer-approval-workflow

Where,

  • Category – Name of the workflow category.
  • Query – Name of the query.
  • Document menu item – Name of display menu item for the document form.

The following artifacts will be created:

  • Workflow type
  • Classes
    • Document class which extends WorkflowDocument.
    • EventHandler class which gives implementation to handle different workflow events.
    • SubmitManager class.
  • Action menu items:
    • SubmitMenuItem pointing to SubmitManager class.
    • CancelMenuItem pointing to WorkflowCancelManager class.

8. Enable Workflow on CustTable and CustTableListPage form by setting Design node properties as follows:

  • WorkflowEnabled – Yes.
  • WorkflowDatasource – Name of the form datasource, CustTable.
  • WorkflowType – Name of the custom workflow type created.

9. Give submit logic in SubmitManager class.

public static void main(Args _args)
{
    MzkCustWorkflowTypeSubmitManager submitManager;

    submitManager = new MzkCustWorkflowTypeSubmitManager();
    submitManager.submit(_args);
}
public void submit(Args _args)
{
    RecId                 _recId;
    WorkflowCorrelationId _workflowCorrelationId;
    workflowTypeName      _workflowTypeName;
    WorkflowComment       _initialNote;
    WorkflowSubmitDialog  workflowSubmitDialog;

    _recId = _args.record().RecId;
    _workflowTypeName = workFlowTypeStr("MzkCustWorkflowType");
    _initialNote = "";

    // Opens the submit to workflow dialog.
    workflowSubmitDialog = WorkflowSubmitDialog::construct(
	_args.caller().getActiveWorkflowConfiguration());

    workflowSubmitDialog.run();

    if (workflowSubmitDialog.parmIsClosedOK())
    {
        _recId = _args.record().RecId;
        // Get comments from the submit to workflow dialog.
        _initialNote = workflowSubmitDialog.parmWorkflowComment();

        try
        {
            ttsbegin;

            _workflowCorrelationId = Workflow::activateFromWorkflowType(
		_workflowTypeName, _recId, _initialNote, NoYes::No);

            ttscommit;

            // Updates the workflow button to diplay Actions instead of Submit.
            _args.caller().updateWorkflowControls();

            info("Submitted to workflow.");
        }
        catch(exception::Error)
        {
            error("Error on workflow activation.");
        }
    }
}

10. Create a Workflow Approval element using the wizard.

customer-approval-workflow

11. Drag the newly created approval to the Supported elements node of the custom workflow type.
12. Define workflow type event handlers in workflow type event handler class.

class MzkCustWorkflowTypeEventHandler implements
    WorkflowCanceledEventHandler,
    WorkflowCompletedEventHandler,
    WorkflowStartedEventHandler
{
}
public void started(WorkflowEventArgs _workflowEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Submitted);
}
public void completed(WorkflowEventArgs _workflowEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Completed);
}
public void canceled(WorkflowEventArgs _workflowEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Canceled);
}

13. Define approval element event handlers in workflow approval element event handler class.

class MzkCustWFApprovalEventHandler implements
    WorkflowElementCanceledEventHandler,
    WorkflowElemChangeRequestedEventHandler,
    WorkflowElementCompletedEventHandler,
    WorkflowElementReturnedEventHandler,
    WorkflowElementStartedEventHandler,
    WorkflowElementDeniedEventHandler,
    WorkflowWorkItemsCreatedEventHandler
{
}
public void started(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowElementEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Submitted);
}
public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowElementEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::ChangeRequested);
}
public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowElementEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::PendingCancelation);
}
public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowElementEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Completed);
}
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
	_workflowElementEventArgs.parmWorkflowContext().parmRecId(),
	MzkCustWFApprovalStatus::Returned);
}
public void created(WorkflowWorkItemsEventArgs _workflowWorkItemsEventArgs)
{
    CustTable::mzkUpdateWorkflowStatus(
        _workflowWorkItemsEventArgs.parmWorkflowElementEventArgs().parmWorkflowContext().parmRecId(),
        MzkCustWFApprovalStatus::Created);
}

14. Define the resubmit action manager class.

public class MzkCustWFApprovalResubmitActionMgr
{
}
public static void main(Args _args)
{
    RecID                        recID;
    TableId                      tableId;
    CustTable                    custTable;
    WorkflowWorkItemTable        workItem;
    WorkflowWorkItemActionDialog workflowWorkItemActionDialog;
    
    recID = _args.record().RecId;
    tableId = _args.record().TableId;
    custTable = _args.record();
    workItem = _args.caller().getActiveWorkflowWorkItem();

    if (workItem.RecId > 0)
    {
        try
        {
            workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct(
                workItem,
                WorkflowWorkItemActionType::Resubmit,
                new MenuFunction(_args.menuItemName(),_args.menuItemType()));

            workflowWorkItemActionDialog.run();

            if (workflowWorkItemActionDialog.parmIsClosedOK())
            {
                if (custTable.MzkWorkflowApprovalStatus ==
			MzkCustWFApprovalStatus::ChangeRequested)
                {
                    workItem = _args.caller().getActiveWorkflowWorkItem();
                    WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem,
                        workflowWorkItemActionDialog.parmWorkflowComment(),
                        workflowWorkItemActionDialog.parmTargetUser(),
                        WorkflowWorkItemActionType::Resubmit,
                        _args.menuItemName(),
                        false);

                    custTable.MzkWorkflowApprovalStatus
			= MzkCustWFApprovalStatus::Submitted;

                    ttsbegin;
                    custTable.dataSource().write();
                    ttscommit;
                }
                else
                {
                    throw Exception::Error;
                }
            }
        }
        catch(Exception::Error)
        {
            throw error(strfmt("Cannot resubmit workflow."));
        }
    }

    _args.caller().updateWorkflowControls();
}

15. Design the Workflow.

  • Navigate to Accounts receivable > Setup > Accounts receivable workflows.
  • Create a new workflow instance of the workflow type you created.
  • Define the states from Start to End of the workflow.
    • Drag approval element from Toolbox on the left to the Designer pane on the right.
    • Connect the bottom of Start state with top of the Approval element.
    • Connect the bottom of Approval element to the top of End state.
  • Resolve any errors and warnings by setting workflow and approval element properties.
  • Activate it.

customer-approval-workflow

16. Test the workflow. You should be able to see the workflow bar.

customer-approval-workflow


Advertisements

8 thoughts on “AX 2012: Create Custom Workflow

  1. Hi,
    I am having requirement about workflow that Employee Transfer is standard workflow
    but when i am attching some conditions to workflow those customised field like Department,Branch,Counter is not in those condition.

    Can you tell me how to deal with this requirement.

    Thanks,
    Manali

  2. I written the following code in the submit method

    TestExpenseTable testexpense;
    WorkflowComment note=””;
    WorkflowSubmitDialog workflowSubmitDialog;

    workflowSubmitDialog = WorkflowSubmitDialog::construct(_args.caller().getActiveWorkflowConfiguration());
    workflowSubmitDialog.run();
    if (workflowSubmitDialog.parmIsClosedOK())
    {
    testexpense = _args.record();
    // Get comments from the submit to workflow dialog.
    note = workflowSubmitDialog.parmWorkflowComment();
    try
    {

    ttsbegin;
    testexpense.TestExpensestatus = TestExpensestatus::submit;
    ttscommit;
    // Send an Infolog message.
    info(“Submitted to workflow.”);
    }

    catch (Exception::Error)
    {
    error(“Error on workflow activation.”);
    }
    }

    _args.caller().updateWorkFlowControls();

  3. I written the following code in the submit method

    TestExpenseTable testexpense;
    WorkflowComment note=””;
    WorkflowSubmitDialog workflowSubmitDialog;

    workflowSubmitDialog = WorkflowSubmitDialog::construct(_args.caller().getActiveWorkflowConfiguration());
    workflowSubmitDialog.run();
    if (workflowSubmitDialog.parmIsClosedOK())
    {
    testexpense = _args.record();
    // Get comments from the submit to workflow dialog.
    note = workflowSubmitDialog.parmWorkflowComment();
    try
    {

    ttsbegin;
    testexpense.TestExpensestatus = TestExpensestatus::submit;
    ttscommit;
    // Send an Infolog message.
    info(“Submitted to workflow.”);
    }

    catch (Exception::Error)
    {
    error(“Error on workflow activation.”);
    }
    }

    _args.caller().updateWorkFlowControls();

  4. HI Mr . Muhammad Anas Khan,
    Thanks for the post,
    11. Drag the newly created approval to the Supported elements node of the custom workflow type.
    I am failing at this point and unable to drag and drop approval type into Workflow type supported elements,
    Can you please suggest the possibilities of this issue.
    Environment : D 365.

    Thanks & Regards,
    Ganesh Vejendla.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s