Skip to main content

Workflow in Ax 2012


In this blog we will discuss custom workflow in ax 2012. Follow below mentioned steps: 

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








HEY HEY HEY!!!! HACK OF THE DAY!!
Always remember to check the WORKFLOW CATEGORY module property should be same as the workflow form Enum Parameter value.

Comments

Popular posts from this blog

Edit Method on Form

Edit Method D365 for a form Data Source 1. To create an edit method first create a controller class. with following properties  public static edit MainAccountNum LedgerJournalTransLedger(LedgerJournalTrans _ledgerjournal, boolean _set, MainAccountNum _id) { MainAccountNum accountId = _id; MainAccount mainAccount = MainAccount::findByMainAccountId(_id); if(_set) { if(_ledgerjournal.AccountType== LedgerJournalACType::Ledger) { mainAccount = MainAccount::findByMainAccountId(accountId); if(_ledgerjournal.LedgerDimension) { DimensionDefault defaultDim = LedgerDimensionFacade::getDefaultDimensionFromLedgerDimension(_ledgerjournal.LedgerDimension); _ledgerjournal.LedgerDimension = LedgerDimensionDefaultingEngine::getLedgerDimensionFromAccountAndDim(mainAccount.RecId, DimensionHierarchy::getAccountStructure(mainAccount.RecId), defaultDim); } else { _ledgerjournal.LedgerDimension = LedgerDimensionDefaultingEngine::getLedgerDimensionFromAccountAndDim(mainAccount.RecId, DimensionHierarchy::ge...

Lookup and Mandatory fields on Form using Form event Handlers D365

Lookup and Mandatory fields on Form using Form event Handlers D365 [FormControlEventHandler(formControlStr(VendBankAccounts, VendBankAccount_SLD_BankCode), FormControlEventType::Lookup)] public static void VendBankAccount_SLD_BankCode_OnLookup(FormControl sender, FormControlEventArgs e)     {         Query query = new Query();         QueryBuildDataSource queryBuildDataSource;         FormControlCancelableSuperEventArgs event = e as FormControlCancelableSuperEventArgs;         QueryBuildRange queryBuildRange;         SysTableLookup sysTableLookup = SysTableLookup::newParameters(tableNum(SLD_BankCodes), sender);         sysTableLookup.addSelectionField(fieldNum(SLD_BankCodes, BankCodes));         sysTableLookup.addLookupField(fieldNum(SLD_BankCodes, BankCodes));         sysTableLookup.addLookupField(fieldNum(SLD_BankCode...

Field Level Security In Ax 2012

FIELD LEVEL SECURITY IN AX 2012 In this blog we will discuss field level security applied in  Ax 2012. 1. Field level security is added on form level as well in Ax 2012 its bit different then field level security in D365 2. This also requires privileges to be applied on form specific fields only. Step #1 :  Change datasource property of the field which need to be added in security. Step #2 : Now add these 2 fields in form --- > permissions --- > Read Step #3 : Now finally create privilege and add these fields explicitly in it.       HEY HEY HEY !!!! HACK OF THE DAY  Add Fields in Entry point privilege section of form  Explicitly.