Wednesday, 5 March 2025

Add a validation on workflow actions

In Dynamics 365FO, workflows can involve a variety of actions such as Approve, Reject, Delegate, and Request Change. There may be scenarios where you need to add validation when a user performs any of these actions.

We encountered a similar situation where we needed to implement a validation process whenever a user performs one of these workflow actions. After investigating, we found that the WorkflowWorkItemActionManager class is triggered when such actions are executed by a user.

Solution -

To add the validation, we can extend the WorkflowWorkItemActionManager class and modify the dispatchWorkItemAction() method. Here's an example of how to extend the class and apply the validation logic:


[ExtensionOf(classStr(WorkflowWorkItemActionManager))]

final class Custom_WorkflowWorkItemActionManagerCls_Extension

{

}


public static void dispatchWorkItemAction( WorkflowWorkItemTable _workItem,                                                                                               WorkflowComment _comment,                                                                                                       WorkflowUser _toUser,                                                                                                                  WorkflowWorkItemActionType                                                                                                      _workItemActionType,                                                                                                                  menuItemName _menuItemName,                                                                                                Name _queueName)

    {  

           WorkflowTypeName    workflowTypeName; 


          //Get the context RecId - for which table the workflow is being executed.     

            RefRecId contextRecId =                                                                                                               WorkflowTrackingStatusTable::findByCorrelation(_workItem.CorrelationId).ContextRecId;


             //For instance, it is a LedgerJournalTable then you can take a journalTable buffer                            using context RecId as below -

            LedgerJournalTable journalTable     = LedgerJournalTable::findByRecId(contextRecId);                        

            //Get the workflow template name, there may be specific 

               template to which validation needs to be applied.

            workflowTypeName = WorkflowTable::findSequenceNumber(WorkflowTrackingStatusTable::

            findByCorrelation(_workItem.CorrelationId).ConfigurationNumber).TemplateName;


           //Check the workflow Action Item type, for which you need to add a validation.

           if (_workItemActionType == WorkflowWorkItemActionType::RequestChange ||

                   _workItemActionType == WorkflowWorkItemActionType::Delegate ||

                    _workItemActionType == WorkflowWorkItemActionType::Return ||

                    _workItemActionType == WorkflowWorkItemActionType::Complete)

        {

            //Declare a set with menu item names for which the validations to be performed.

                     Set menuItemSet = new Set(Types::String);

                    menuItemSet.add(Custom_ConstantHelper::LedgerApprove);       

                    menuItemSet.add(Custom_ConstantHelper::LedgerReject);  

                    menuItemSet.add(Custom_ConstantHelper::LedgerRequestChange); 

                    menuItemSet.add(Custom_ConstantHelper::LedgerDelegate);    


                     if (menuItemSet.in(_menuItemName))

                    {

                        if (Add your validation method call)

                        {

                            throw error("Validation failed");

                        }

                    }

           }

}

        

Extending WorkflowWorkItemActionManager - By extending WorkflowWorkItemActionManager class, you can inject your custom logic for additional validation.
Context RecId: The context of the workflow action is determined using the CorrelationId of the work item, which helps you fetch the corresponding record (in this case, a LedgerJournalTable).
Validation Logic: The validation is added only for specific workflow actions such as Request Change, Delegate, Return, and Complete. You can customize the actions for which the validation should apply.
Menu Item Validation: A set of menu items is defined, and if the current menu item matches any item in the set, the validation method is invoked. If the validation fails, an error is thrown, preventing the action from being completed.

This approach ensures that the workflow actions are validated appropriately, adding an extra layer of control to your functionality.

Sunday, 2 March 2025

Arrange report parameters in one column - UI Builder

Sometimes customer has requirement to have the specific design changes on report/parameter dialog, we came across one of such requirements to have all report parameters in one column of the dialog. This can be achieved with code of couple of lines in build method of UI builder class.

Here’s a code sample demonstrating how this can be done:


/// <summary>

/// UI builder class for managing report control

/// </summary>

class Demo_ReportUIBuilder extends SrsReportDataContractUIBuilder

{

    DialogField dialogField1;

    DialogField dialogField2;


    /// <summary>

    /// Overriden method to handle the report dialog controls

    /// </summary>

    public void build()

    {

        super();


        dialogField1 =  this.bindInfo().getDialogField(this.dataContractObject(),

    methodStr(Demo_ReportContract, parmField1));

 

                //Set as mandatory

         dialogField1.fieldControl().mandatory(true);


        dialogField2 = this.bindInfo().getDialogField(this.dataContractObject(),methodStr(Demo_ReportContract, parmField2));

        

//Code to arrange fields in one column -

        SysOperationDialog dlg = dialog as SysOperationDialog;

        dlg.mainFormGroup().columns(1);

    }

}


Binding Parameters: We used the getDialogField() method to bind the report parameters to dialog fields. In this example, parmField1 and parmField2 are the parameters being used.
Mandatory Field: The mandatory(true) method is used to set parmField1 as a mandatory field for the report.
Single Column Layout: To arrange all the report parameters in a single column, we accessed the SysOperationDialog and used the mainFormGroup().columns(1) method to set the layout to one column.

If you want to display the parameters in multiple columns, you can modify the columns() value accordingly.

Filtering Company-Specific Product Templates - SysRecordTmpTemplate lookup

Hi Techies - Recently I have come across a requirement where I needed to display product templates specific to a selected company for a give...