Skip to main content

Notifications

Announcements

No record found.

Community site session details

Community site session details

Session Id :
Finance | Project Operations, Human Resources, ...
Answered

Multiple line approval for workflows

(0) ShareShare
ReportReport
Posted on by 323

Hi All,

I have a requirement to approve multiple workitems assigned to me.

There are many threads on this but no proper solution is available. 
please help.

Thanks,

Priya

  • GirishS Profile Picture
    27,825 Moderator on at
    RE: Multiple line approval for workflows

    Please mark the helpful answers as verified, so others can make use of this thread.

    Thanks,

    Girish S.

  • PriyaDutta Profile Picture
    323 on at
    RE: Multiple line approval for workflows

    Hi Girish,

    I just checked that while passing user in below statement

     WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem,'Delegated',curUserId(),
                           WorkflowWorkItemActionType::Delegate,menuItemActionStr(TSworkflowDelegate),'WorkflowApproval');
                           

    In standard , they are passing _toUser  value , whereas in my code current user is getting passed, due to which the both toUser and fromUser values are same.

    So,I have updated the code to fetch target user .

    WorkflowWorkItemActionDialog workflowWorkItemActionDialog;
    
                workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct(workItem,
                                                                                   WorkflowWorkItemActionType::Delegate,
                    new MenuFunction(menuItemActionStr(TSworkflowDelegate),MenuItemType::Action),
                                                                                    'Action');
                workflowWorkItemActionDialog.run();
    
              
                if (workflowWorkItemActionDialog.parmIsClosedOK())
                    {
                        WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem,'Delegated',workflowWorkItemActionDialog.parmTargetUser(),
                           WorkflowWorkItemActionType::Delegate,menuItemActionStr(TSworkflowDelegate),'WorkflowApproval');
               
                    }

    Its working fine now.

    Thanks for your help,

    Priya

  • Verified answer
    GirishS Profile Picture
    27,825 Moderator on at
    RE: Multiple line approval for workflows

    From the error I think "curUserId" already has a work item assigned for the same workflow step. Check what is the value of _toUser and  _fromUser in the arguments of delegate method.

    Also open the WorkflowWorkItemTable and see whether the delegated user has already a work Item assigned.

    Thanks,

    Girish S.

  • PriyaDutta Profile Picture
    323 on at
    RE: Multiple line approval for workflows

    Hi Girish,

    Thanks for your help.

    I am able to now Approve and Reject multiple timesheets for review.

    But I am struggling with Delegation.

    I am getting below error on clicking 'Delegate'.

    pastedimage1678365162749v1.png

    Please find the below code .

    internal final class MassTimeDelegate
    {
        public static void main(Args args)
        
        {
           // FormDataSource                  ds = args.record().dataSource();
            FormDataSource                  ds = FormDataUtil::getFormDataSource( args.record());
            Common                          record;
            WorkflowWorkItemTable           workitem;
            //WorkflowComment                 comment;
            //MenuItemName                    menuitem;
            //str                             label;
            WorkflowWorkItemActionType      action;
          
            
            
            action = WorkflowWorkItemActionType::Delegate;
          
            
            for(record = ds.getFirst(true) ? ds.getFirst(true) : ds.cursor(); record; record = ds.getNext())
            
            {
                
    
                select * from workItem
                    where workItem.UserId == curUserid() && workItem.RecId == record.RecId;
               
               
    
                WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem,'Delegated',curUserId(),
                           WorkflowWorkItemActionType::Delegate,menuItemActionStr(TSworkflowDelegate),'WorkflowApproval');
               
              
               
    
            }
            ds.research();
            ds.refresh();
    
            
        }

    On debugging I find error is being thrown after below statement

    pastedimage1678365417826v2.png

    Not sure what is the issue. When i am going to standard form "Work items assigned to me " I am able to delegate  work items.

    Please help.

    Thanks ,

    Priya

  • Verified answer
    GirishS Profile Picture
    27,825 Moderator on at
    RE: Multiple line approval for workflows

    No need to create new workflow - Use the standard workflow menu items.

    Thanks,

    Girish S.

  • PriyaDutta Profile Picture
    323 on at
    RE: Multiple line approval for workflows

    Hi Girish,

    So should I create new workflow or can I use the standard workflow and the menu items already present. 

  • Suggested answer
    GirishS Profile Picture
    27,825 Moderator on at
    RE: Multiple line approval for workflows

    It's related to the workflow completed action menu item. While creating workflows action menu item will be created. You can find that in workflow types- property name will be CompletedEventHandler.

    If its a timesheet workflow then menu item name will be TSWorkflowEventHandler.

    Thanks,

    Girish S.

  • PriyaDutta Profile Picture
    323 on at
    RE: Multiple line approval for workflows

    Hi Girish,

    By approval menu item you mean the menu item button that is created in the form calling the action menu item “MassTimeApproval” ?

  • Verified answer
    GirishS Profile Picture
    27,825 Moderator on at
    RE: Multiple line approval for workflows

    On your code - Line number 174, you are getting the work item by calling the getActiveWorkitemForRecord. After that code just call the below piece of code.

    You know the Approval menu item for timesheet - Just mention the action menu item name itself - No need to write separate method to get the action approval menu item.

    WorkflowWorkItemActionManager::dispatchWorkItemAction(workItem,"Approved",curUserId(),
                            WorkflowWorkItemActionType::Complete,menuItemActionStr(YourWorkflowApprovalMenuItem2),"WorkflowApproval");
                            break;

    You can comment all the other codes after that.

    If not working properly, debug the code and find out on which line it gets failed.

    Thanks,

    Girish 

  • PriyaDutta Profile Picture
    323 on at
    RE: Multiple line approval for workflows

    Hi Girish,

    I found the below piece of code. Can you tell me where should I add the above code.

    internal final class MassTimeApproval
    {
        public static void actionItem(WorkflowWorkItemActionType action, WorkflowWorkItemTable _workitem, WorkflowComment _comment,MenuItemName _menuItem )
            
        {
               WorkflowWorkItemActionManager::dispatchWorkItemAction(_workitem,
                                                                            _comment,
                                                                            '',
                                                                            action,
                                                                            _menuItem,
                                                                            '');
            
        }
    
            public static WorkflowWorkitemTable getActiveWorkitemForRecord(Common _buffer)
        
        {
                WorkflowWorkitemTable           workitem;
                RecId                           refRecid = _buffer.RecId;
                TableId                         refTableId = _buffer.TableId;
            
                select workitem where workitem.RefRecId == refRecid && workitem.RefTableId == refTableId
                    && (workitem.Status == WorkflowWorkItemStatus::Pending || workitem.Status == WorkflowWorkItemStatus::Delegated);
            
                return workitem;
            
        }
    
            public static container getMenuItemForType(WorkflowWorkItemtable _workitem, WorkflowWorkItemActionType _type, UserId user)
        
        {
                #Workflow
            
                WorkflowElementTable            workflowElement;
                SysDictWorkflowElement          dictWorkflowElem;
            
                WorkflowConfigOutcome           workflowConfigOutcome;
                WorkflowWorkItemActionType      workItemActionType;
            
                Map                             actionList;
                MapEnumerator                   actionListEnum;
                Map                             outcomeList;
                MapEnumerator                   outcomeListEnum;
            
                SysDictMenu                     sysDictMenu;
            
                MenuItemName                    mi;
            //WorkflowWorkItemActionDelegate WorkflowWorkItemActionDelegate;
            
                container ret = ["",""];
                ;
                if (_workitem.Type != WorkflowWorkItemType::Recall)
            
            {
                        workflowElement = WorkflowElementTable::find(_workitem.ElementId);
                        if (workflowElement.RecId != 0)
                
                {
                                dictWorkflowElem = new SysDictWorkflowElement(workflowElement.ElementType, workflowElement.ElementName);
                    
                                if (_workitem.Type == WorkflowWorkItemType::RequestChange || _workitem.Type == WorkflowWorkItemType::Return)
                    
                    {
                                        //ADD RESUBMIT ITEMS
                                        mi = dictWorkflowElem.resubmitMenuItem();
                                        sysDictMenu = SysDictMenu::newMenuItem(mi,MenuItemType::Action);
                                        if (_type == WorkflowWorkItemActionType::Resubmit)
                        
                        {
                                                ret = [mi, sysDictMenu.label()];
                                                return ret;
                            
                        }
                        
                    }
                                else
                    
                    {
                        
                                        workflowConfigOutcome = workflowElement.getElementOutcomes();
                        
                                        actionList = workflowConfigOutcome.parmActionList();
                                        actionListEnum = actionList.getEnumerator();
                        
                                        outcomeList = workflowConfigOutcome.parmOutcomList();
                                        outcomeListEnum = outcomeList.getEnumerator();
                        
                                        while (outcomeListEnum.moveNext())
                        
                        {
                                                if (outcomeListEnum.currentValue() == NoYes::Yes)
                            
                            {
                                                        mi = dictWorkflowElem.actionMenuItem(outcomeListEnum.currentKey());
                                                        sysDictMenu = SysDictMenu::newMenuItem(mi,MenuItemType::Action);
                                                        workItemActionType = WorkflowWorkItemActionManager::findActionTypeForMenuItem(_workitem, mi);
                                                        if (workItemActionType == _type)
                                
                                {
                                                                if (sysDictMenu)
                                    
                                    {
                                                                        ret = [mi, sysDictMenu.label()];
                                                                        break;
                                        
                                    }
                                    
                                }
                                
                            }
                            
                        }
                        
                                        if (_type == WorkflowWorkItemActionType::Delegate)
                        
                        {
                                                while (actionListEnum.moveNext())
                            
                            {
                                                        // make sure action is enabled
                                                        if (actionListEnum.currentValue() == NoYes::Yes)
                                
                                {
                                                                if (actionListEnum.currentKey() == #WorkflowWorkItemActionDelegate)
                                    
                                    {
                                                                        // allow delegate if work item is not a final approver work item
                                                                        if (_workitem.Type != WorkflowWorkItemType::FinalApprover)
                                        
                                        {
                                                                                mi = dictWorkflowElem.delegateMenuItem();
                                                                                sysDictMenu = SysDictMenu::newMenuItem(mi,MenuItemType::Action);
                                                                                ret = [mi, sysDictMenu.label()];
                                            
                                        }
                                        
                                    }
                                    
                                }
                                
                            }
                            
                        }
                        
                    }
                    
                }
                
            }
                return ret;
            
        }
    
            public static void main(Args args)
        
        {
                FormDataSource                  ds = args.record().dataSource();
                Common                          record;
                WorkflowWorkItemTable           workitem;
                WorkflowComment                 comment;
                MenuItemName                    menuitem;
                str                             label;
                WorkflowWorkItemActionType      action;
                boolean                         commented;
                WorkflowWorkItemActionDialog    dialog;
                TSTimesheetTable                tsTimesheetTable;
            
            
                action = WorkflowWorkItemActionType::Complete;
            
                for(record = ds.getFirst(true) ? ds.getFirst(true) : ds.cursor(); record; record = ds.getNext())
            
            {
                        workitem = MassTimeApproval::getActiveWorkitemForRecord(record);
                        if (workitem)
                
                {
                    [menuitem,Label] = MassTimeApproval::getMenuItemForType(workitem, action , curUserId());
                                if (!commented)
                    
                    {
                                        dialog = WorkflowWorkItemActionDialog::construct(workitem, action, new MenuFunction(menuitem, MenuItemType::Action));
                                        dialog.run();
                                        if (dialog.parmIsClosedOK())
                        
                        {
                                                commented = true;
                                                comment = dialog.parmWorkflowComment();
                            
                        }
                                        else
                        
                        {
                                                break;
                            
                        }
                        
                    }
                                if (menuitem)
                    
                    {
                        MassTimeApproval::actionItem(action, workitem,comment,menuitem);
                                        tsTimesheetTable = TSTimesheetTable::findRecId(record.RecId);
                                        if(tsTimesheetTable)
                        
                        {
                                                SourceDocumentProcessorFacade::submitSourceDocumentImplementation(tsTimesheetTable, false, SourceDocumentAccountingStatus::Completed);
                            
                        }
                        
                    }
                                else
                    
                    {
                                        error(strFmt("No %1 action defined for item %2", action, record.caption()));
                        
                    }
                    
                }
                
            }
                ds.research();
                ds.refresh();
            
            
        }
    
    }

    Thanks,

    Priya

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Understanding Microsoft Agents - Introductory Session

Confused about how agents work across the Microsoft ecosystem? Register today!

Jonas ”Jones” Melgaard – Community Spotlight

We are honored to recognize Jonas "Jones" Melgaard as our April 2025…

Kudos to the March Top 10 Community Stars!

Thanks for all your good work in the Community!

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 294,430 Super User 2025 Season 1

#2
Martin Dráb Profile Picture

Martin Dráb 233,043 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,158 Moderator

Leaderboard

Product updates

Dynamics 365 release plans