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.
Development:
1. Create a workflow status Enum to have the following elements:
2. Add field of type workflow status enum to the CustTable table.
3. Override canSubmitToWorkflow() method of CustTable table to define workflow submission criteria.
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.
6. Create a Workflow Category.
7. Create a Workflow Type using wizard.
7. Create a Workflow Type using wizard.
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.
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.
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.
16. Test the workflow. You should be able to see the workflow bar.