Auto Approve Workflow by Code x++

Example code :

static void TIDF_autoApproveWFOvertime(Args _args)
{
    WorkflowWorkItemTable WorkflowWorkItemTable;

    while select WorkflowWorkItemTable
    where
        WorkflowWorkItemTable.UserId == '32501112'
    &&  workflowWorkItemTable.Type == WorkflowWorkItemType::WorkItem
    &&  workflowWorkItemTable.Status == WorkflowWorkItemStatus::Pending
    &&  WorkflowWorkItemTable.RefTableId == tableNum(HrsOvertime)
    {
        WorkflowWorkItemActionManager::dispatchWorkItemAction(
                                    WorkflowWorkItemTable,
                                    "Auto Approve by ADMIN", // comment
                                    '32501112', // << user ID
                                    WorkflowWorkItemActionType::Complete,
                                    "HRSOvertimeApprove", // << menu item action approval workflow
                                    false); //is not web Menu Item
    }

}

Capture

Advertisements

Hide(remove) menu item action approval workflow

Some of our clients don’t need “Delegate” or “Deny” on workflow,
so here below is how to hide Workflow Approval menu items,

just remove “ActionMenuItems” and “WebActionMenuItems” for web on the Workflow Approval AOT properties.
Capture.PNG

do Full CIL and Incremental CIL after remove the properties,
menu items will be remove from workflow user approval.

result
Capture

check user workflow hierarchy by code x++

i found a nice code for checking user workflow hierarchy approver and solved the related error.

static void navax_workflowHierarchyTester(Args _args)
{
    WorkflowTypeName                    workflowTemplateName = 'TIDEmploymentLeave';
    //TrvExpTrans                         trvExpTrans;
    //TrvExpNumber                        trvExpNum = '000015'; //Expense id

    HcmEmploymentLeave                  hcmEmploymentLeave;
    str                                 nodeId = '23511014'; //Starting worker id
    WorkflowHierarchyLevel              level = 0;
    WorkflowContext                     workflowContext;
    SysWorkflowTable                    workflowTable;
    WorkflowLimitHierarchyProvider      workflowLimitHierarchyProvider;
    WorkflowHierarchyProviderNode       workflowHierarchyProviderNode;
    HRPWorkerLimit                      workerLimit = new HRPWorkerLimit();
    HcmWorker                           hcmWorker;
    DirPersonUser                       dirPersonUser;
    RefRecId                            hcmPositionRecId;
    HcmPosition                         hcmPosition;
    container                           spendingCon, approvalCon;
    UserId                              userId;

    select firstOnly workflowTable
        where workflowTable.TemplateName == workflowTemplateName;

    select firstOnly hcmEmploymentLeave
        where hcmEmploymentLeave.HRSLeaveReqId ==  &quot;LV-00635&quot; ;

    workflowContext = WorkflowContext::newWorkflowContext(
        curext(),
        tableNum(hcmEmploymentLeave),
        hcmEmploymentLeave.RecId,
        workflowTable.WorkflowCorrelationId);

    workflowLimitHierarchyProvider = new WorkflowLimitHierarchyProvider();

    //Level 1
    while (nodeId &amp;&amp; level &lt; 20) //20 is just a fall back. In case it goes into an endless loop.
    {
        workflowHierarchyProviderNode   = workflowLimitHierarchyProvider.getNextNode(nodeId, level, workflowContext);
        nodeId                          = workflowHierarchyProviderNode.getnodeId();
        hcmWorker                       = HcmWorker::findByPersonnelNumber(nodeId);
        userId                          = DirPersonUser::findParty(hcmWorker.Person).User;
        hcmPositionRecId                = HcmWorker::getPrimaryPosition(hcmWorker.RecId);
        hcmPosition                     = HcmPosition::find(hcmPositionRecId);

        spendingCon = workerLimit.getWorkerSigningLimit(
            hcmWorker.RecId,
            SourceDocumentRelationType::ExpenseReport,
            HRPLimitType::Spending,
            hcmPosition.PositionId);

        approvalCon = workerLimit.getWorkerSigningLimit(
            hcmWorker.RecId,
            SourceDocumentRelationType::ExpenseReport,
            HRPLimitType::Approval,
            hcmPosition.PositionId);

        info(strFmt(&quot;UserId: %1 | WorkerId: %2 | PositionId: %3 | ReportsToPosition: %4 | SpendingLimit: %5 | ApprovalLimit: %6&quot;,
            userId,
            hcmWorker.PersonnelNumber,
            hcmPosition.PositionId,
            hcmPosition.reportsToPosition(),
            con2Str(spendingCon),
            con2Str(approvalCon)
            ));

        level++;
    }
}

source :
https://community.dynamics.com/ax/b/dynamicsnavax/archive/2015/06/08/workflow-hierarchy-assignment-common-errors-explained-and-tester-job-ax-2012

example custom code submitManager class for both Rich Client and EP (Enterprise Portal) x++

differentiate the rich client and ep using the menu items name.
always remember to do INCREMENTAL CIL every time you modify any of workflow classses

public void submit(Args _args)
{
    WorkflowComment         note = "";
    WorkflowSubmitDialog    workflowSubmitDialog;
    WorkflowCorrelationId   workflowCorrelationId;
    recId                   recId;
    workflowTypeName        workflowTypeName = workflowtypestr("TIDEmploymentLeave");
    WorkflowComment         initialNote = "";
    HcmEmploymentLeave      HcmEmploymentLeave;
    FormDataSource          HcmEmploymentLeave_ds;
    EPWorkflowControlContext workflowControlContext;
    str                     menuItemName = _args.menuItemName();


    //from rich client
    if(menuItemName == menuitemactionstr(TIDEmploymentLeaveSubmitMenuItem) || menuItemName == menuitemActionStr(HRSLeaveCreditSubmitMenuItem))
    {
        // Workflow is starting from the Windows client. This can be determined
        // because the menu item for submitting the workflow on the Windows
        // client was chosen by the user.

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

        if (workflowSubmitDialog.parmIsClosedOK())
        {
            // Find what record from the Work Orders table is being submitted to workflow.
            recId = _args.record().RecId;

            // Get comments from the submit to workflow dialog.
            initialNote = workflowSubmitDialog.parmWorkflowComment();

            try
            {
                // Update the record in the FCMWorkOrders table that is being submitted to workflow.
                // The record is moved to the 'submitted' state.
                ttsBegin;
                HcmEmploymentLeave = _args.record();
                HcmEmploymentLeave.selectForUpdate(true);
                HcmEmploymentLeave.Status = HRSLeaveStatus::Submitted;
                HcmEmploymentLeave.update();
                // Activate the workflow.
                workflowCorrelationId = Workflow::activateFromWorkflowType(workflowTypeName, recId, initialNote, NoYes::No);

                 ttsCommit;

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

            catch(exception::Error)
            {
                info("Error on workflow activation.");
            }
        }
    }
    //from EP
    else
    {
         // Workflow is starting from Enterprise Portal.

         // Retrieve the workflow controller context from the arguments passed in.
         workflowControlContext = _args.caller();

         // Find what record from the Work Orders table is being submitted to workflow.
         recId = _args.record().RecId;

         // Get comments from the submit to workflow dialog.
         initialNote = workflowControlContext.getWorkflowComment();

        try
        {
            ttsBegin;
            workflowCorrelationId = Workflow::activateFromWorkflowType(workflowTypeName, recId, initialNote, NoYes::Yes);
            HcmEmploymentLeave = _args.record();
            HcmEmploymentLeave.selectForUpdate(true);
            HcmEmploymentLeave.Status = HRSLeaveStatus::Submitted;
            HcmEmploymentLeave.update();
            ttsCommit;
        }
        catch(exception::Error)
        {
            info("Error on workflow activation.");
        }
    }
}

example code on custom class ApprovalResubmitActionMgr

example code :

public static void main(Args _args)
{
    recID                           recID               = _args.record().RecId;
    tableId                         tableId             = _args.record().TableId;
    HcmEmploymentLeave              HcmEmploymentLeave  = _args.record();
    WorkflowWorkItemTable           workItem            = _args.caller().getActiveWorkflowWorkItem();
    str                             menuItemName        = _args.menuItemName();
    WorkflowWorkItemActionDialog    workflowWorkItemActionDialog;
    WorkflowSubmitDialog            workflowSubmitDialog;
     
    Debug::assert(tableId == tablenum(HcmEmploymentLeave));
    Debug::assert(recId != 0);

    // The method has not been called correctly.
    if (tableId != tablenum(HcmEmploymentLeave) ||
        recId == 0)
    {
        throw error(strfmt("@SYS19306", funcname()));
    }

    // The journal has an active workflow.
    if (workItem.RecId > 0)
    {
        try
        {
            // The journal does support workflow approvals.
            workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct( workItem,
                                                                                    WorkflowWorkItemActionType::Resubmit,
                                                                                    new MenuFunction(_args.menuItemName(),_args.menuItemType()));
            workflowWorkItemActionDialog.run();
            if (workflowWorkItemActionDialog.parmIsClosedOK())
            {

                workItem    = _args.caller().getActiveWorkflowWorkItem();
                WorkflowWorkItemActionManager::dispatchWorkItemAction(  workItem,
                                                                    workflowWorkItemActionDialog.parmWorkflowComment(),
                                                                    workflowWorkItemActionDialog.parmTargetUser(),
                                                                    WorkflowWorkItemActionType::Resubmit,
                                                                    _args.menuItemName(),
                                                                    false);
              
            }
        }

        catch(Exception::Error)
        {
            throw error(strfmt("Leave %1 can't be submitted", HcmEmploymentLeave.HRSLeaveReqId));
        }
    }
    // Make the form refresh its common workflow UI controls.
    _args.caller().updateWorkflowControls();
}