Tuesday, February 17, 2026

Run some logic in workflow at particular step using WorkflowAutomatictask

 Scenario:- If you want to run some logic in workflow at particular we can use WorkflowAutomatictask

Step1:- create a class 

 Code:-

       class CustomWorkflowAutomatedEvnentHandler implements WorkflowElementExecutionEventHandler

{
    public void execute(WorkflowElementEventArgs _workflowElementEventArgs)
    {
        WorkflowContext    workflowContext = _workflowElementEventArgs.parmWorkflowContext();

 

        RecId recid = workflowContext.parmRecId();

 

        EmployeeTable emptable;

 

        select * from emptable where emptable.RecId == recid;

 

        info(strFmt("%1",emptable.EmployeeId));
    }

 

}

Step2:- Add Workflowautomatictask and give properties as shown in below

Step3:-In the supported elements add this automatic task and give type as automatictask.

Step4:-Open frontend and drag this automatictask to run some logic as shown in below

Thankyou!!

Add approvers at runtime using Assignment provide class in D365fo

 Step1:-Create a class code as follows

Code;- 

        class CustomworkflowAssignmentProviderClass implements WorkflowParticipantprovider

{
    public WorkflowParticipantTokenList getParticipantTokens()
    {
        WorkflowParticipantTokenList tokens = WorkflowParticipantTokenList::construct();

        tokens.add("Level1","Level 1");
        return tokens;
    }

 

    public WorkflowUserList resolve(WorkflowContext _context,
                                    WorkflowParticipantToken _participantTokenName)
    {
        WorkflowUserList    userList = WorkflowUserList::construct();

 

        EmployeeTable emptable;
        UserGroupInfo usergroupinfo;
        UserGroupList usergrouplist;

 

       

 


        switch(_participantTokenName)
        {
            case "Level1" :
                select * from emptable
            where emptable.RecId == _context.parmRecId();

 

                if(emptable.AssigneeType == AssigneeType::User)
                {
                    userList.add(emptable.User);

 

                }
                else
                {
                    while select usergrouplist
               where usergrouplist.groupId == emptable.User
                    {
                        userList.add(emptable.User);
                    }

                }
                break;

 


        }


        if (userList.getCount() == 0)
        {
            throw error(strFmt("User can not found"));
        }
        return userList;
    }

 

}

Step2:-Add Workflow participant provide and give AssignmentProviderClass in properties and add

Workflow type with new element give workflow type as shown in below

Step3:-Build and sync then add this assignment provide in assignment section in Workflow configurator

That's all

Thankyou


Monday, February 16, 2026

Custom workflow with drop dialog as standard in d365fo

 If we want get output of workflow like dropdialog as some of standard workflows please follow steps

output expected:-

Step1:-Please develop basic workflow first by using link below

https://manidynamics.blogspot.com/2026/02/custom-workflow-in-d365fo.html

Step2:-Go to any standard forms , here i have chosen Purchtable confirm workflow and locate control as shown in below

Step3:-Go to that form and duplicate similar to your project as shown in below

Step4:-Change cord in Formlevel replace with your table and workflowtype names and in cansubmit instead caller use record.cansubmitworkflow

Step5:-Create  a display menuitem for this form

Step6:-Create a buttongroup control and add button and give properties of menuitem created in above step.Also change normalimage property to Workflow as shown in below

Step7:-Remove formdesign properties workflowtype 

Output :-

configure workflow in frontend .

Thankyou!!

How to develop Custom Workflow in D365fo

In this blog we see all about Workflows development in D365fo 

Output as shown in below




Step1:-Create a base enum with elements as shown in below and name it as Workflowstatus
Step2:-Add it in the table as well as form as shown in below



Step3:-Write code in canSubmitToWorkFlowmethod in Table level , This will make you to submit the workflow in its is Draft allow.

Code:-
public boolean canSubmitToWorkFlow(str _workflowType = "")  
  {        
      boolean ret;           
      ret = super(_workflowType);       
    if (this.WorkflowStatus == WorkflowStatus::Draft)    
    {        
       ret = true;       
    }         
    return ret;   
}

And also write new method for updating workflow status

Code:-
public static void  updateWorkFlowStatus(RefRecId _recId , WorkflowStatus _status)   
   {   
     EmployeeTable   employeeTable;    
      ttsbegin;           
     select firstonly forupdate employeeTable        
      where employeeTable.RecId == _recId;      
    
employeeTable.EmployeeWFStatus = _status;    
    employeeTable.update();       
    ttscommit;    
}

Step4:-Add new Query and drag table into datasource and make Dynamicfields property to YES 
as shown in below
Step 5:-Create a Workflow category and give Module name in property and this will make workflow type available in frontend to configure the workflow steps.Here i am giving Vendor to visible 
in Accounts payable workflows
Step 6:-Add Workflow Type 
And Provide all details created earlier as shown in below:-

Click on next then system itself creates a event handlers, classes as shown in below
Step 7:-Write code in Workflowtype eventhandler class

Code:-
          /// <summary>

/// The CustomWorkflowTypeEventHandler workflow event handler.
/// </summary>
public class  CustomWorkflowTypeEventHandler implements WorkflowCanceledEventHandler,  
  WorkflowCompletedEventHandler,
  WorkflowStartedEventHandler
{
    public void started(WorkflowEventArgs _workflowEventArgs)
  {
    // TODO:  Write code to execute once the workflow is started.
        EmployeeTable::updateWorkFlowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Pending);
  }

 

    public void canceled(WorkflowEventArgs _workflowEventArgs)
  {
    // TODO:  Write code to execute once the workflow is canceled.
        EmployeeTable::updateWorkFlowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Draft);
  }

 

    public void completed(WorkflowEventArgs _workflowEventArgs)
  {
    // TODO:  Write code to execute once the workflow is completed.
        EmployeeTable::updateWorkFlowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Completed);
  }

 

}

Step8:- Add code in Submitmanagerclass

Code:- 

          /// <summary>

/// The CustomWorkflowTypeSubmitManager menu item action event handler.
/// </summary>
public class CustomWorkflowTypeSubmitManager 
{
    public static void main(Args _args)
  {
    //  TODO:  Write code to execute once a work item is submitted.

 

        EmployeeTable                 employeetable;
        CustomWorkflowTypeSubmitManager    submitManger = new CustomWorkflowTypeSubmitManager();
        recId                              _recId =_args.record().RecId;
        WorkflowCorrelationId         _workflowCorrelationId;
        workflowTypeName           _workflowTypeName = workFlowTypeStr("CustomWorkflowType");
        WorkflowComment              note = "";
        WorkflowSubmitDialog        workflowSubmitDialog;

 

        workflowSubmitDialog = WorkflowSubmitDialog::construct(_args.caller().getActiveWorkflowConfiguration());
        workflowSubmitDialog.run();

        if (workflowSubmitDialog.parmIsClosedOK())
        {
            employeetable = _args.record();
            note = workflowSubmitDialog.parmWorkflowComment();
            try
            {
                ttsbegin;
                _workflowCorrelationId = Workflow::activateFromWorkflowType(_workflowTypeName, employeetable.RecId, note, NoYes::No);
                employeetable.WorkflowStatus = WorkflowStatus::Submitted;
                employeetable.update();
                ttscommit;

                info("Submitted to workflow.");
            }
            catch (Exception::Error)
            {

                error("Error on workflow activation.");
            }
        }
        _args.caller().updateWorkFlowControls();
  }

 

}

Step 9:-Add Workflow Approval 

Provide details created in above steps


After clicking next system will create some classes and action menuitems

Step10:-Add code in Approval event handler

Code:-

       /// <summary>

/// The CustomWorkflowApprovalEventHandler workflow outcome event handler.
/// </summary>
public final class CustomWorkflowApprovalEventHandler implements WorkflowElementCanceledEventHandler,
  WorkflowElemChangeRequestedEventHandler,
  WorkflowElementCompletedEventHandler,
  WorkflowElementReturnedEventHandler,
  WorkflowElementStartedEventHandler,
  WorkflowElementDeniedEventHandler,
  WorkflowWorkItemsCreatedEventHandler
{
    public void started(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once the workflow is started.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::InReview);
  }

 

    public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once the workflow is canceled.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Draft);
  }

 

    public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once the workflow is completed.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Completed);
  }

 

    public void denied(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once the workflow is denied.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Rejected);
  }

 

    public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once change is requested for the workflow.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::ChangeRequest);
  }

 

    public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
  {
    // TODO:  Write code to execute once the workflow is returned.
        EmployeeTable::updateWorkFlowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), WorkflowStatus::Rejected);
  }

 

    public void created(WorkflowWorkItemsEventArgs _workflowWorkItemsEventArgs)
  {
    // TODO:  Write code to execute once work items are created.
  }

 

}

Step11:-Write code in Resubmit class

/// <summary>
/// The CustomWorkflowApprovalResubmitActionMgr menu item action event handler.
/// </summary>
public class CustomWorkflowApprovalResubmitActionMgr 
{
    public static void main(Args _args)
  {
    //  TODO:  Write code to execute once work items are resubmitted.

 

        if (!_args.record() || !_args.caller())
        {
            throw error(Error::wrongUseOfFunction(funcName()));
        }

        WorkflowWorkItemTable workItem = _args.caller().getActiveWorkflowWorkItem();
        if (workItem)
        {
            try
            {
                WorkflowWorkItemActionDialog dialog = WorkflowWorkItemActionDialog::construct(
                    workItem,
                    WorkflowWorkItemActionType::Resubmit,
                    new MenuFunction(_args.menuItemName(),_args.menuItemType()));
                dialog.run();

                if (dialog.parmIsClosedOK())
                {
                    workItem = _args.caller().getActiveWorkflowWorkItem();
                    WorkflowWorkItemActionManager::dispatchWorkItemAction(
                        workItem,
                        dialog.parmWorkflowComment(),
                        dialog.parmTargetUser(),
                        WorkflowWorkItemActionType::Resubmit,
                        _args.menuItemName());

                    RecID recID = _args.record().RecId;
                    ttsbegin;
                    EmployeeTable::updateWorkFlowStatus(recID, WorkflowStatus::Submitted);
                    info("@AccountsPayable:VendBankAccountChangeProposalResubmit_Success");
                    ttscommit;
                }
            }
            catch(exception::Error)
            {
                info("@AccountsPayable:VednBankAccountChangeProposalResubmit_Error");
            }
        }

        // make sure changes in status are reflected on the caller
        if (FormDataUtil::isFormDataSource(_args.record()))
        {
            FormDataSource callerDS = FormDataUtil::getFormDatasource(_args.record());



            callerDS.reread();
            callerDS.refresh();
        }
        _args.caller().updateWorkflowControls();
  }

 

}


Step12:-Change labels for action menu items that have been created by systems

Note:- for cancel put Recall

Step13:-In the Workflowtype add in supported elements and in the properties give workflowapproval and give Approval in type as shown in below

Step 14:-In form design properties changes properties of Workflow


Configure workflow in front and assign required approvers.

Thankyou!!

Sunday, February 15, 2026

Generate a URL to navigate to D365fo for email sends

 using Microsoft.Dynamics.AX.Framework.Utilities;

using Microsoft.Dynamics.ApplicationPlatform.Environment;


public static str getRecordURL(str _menuItemName,MenuItemType _menuItemType,DataAreaId _dataArea,str _tableName,str _fieldName,str _fieldValue)
{
     str url;
     IApplicationEnvironment env = EnvironmentFactory::GetApplicationEnvironment();
     str currentUrl = env.Infrastructure.HostUrl;
     System.Uri currentHost = new System.Uri(currentUrl);

     UrlHelper.UrlGenerator generator = new UrlHelper.UrlGenerator();
     UrlHelper.RequestQueryParameterCollection requestQueryParameterCollection;


     generator.HostUrl = currentHost.GetLeftPart(System.UriPartial::Authority);
     generator.Company = _dataArea;
     generator.MenuItemName = _menuItemName;
     generator.MenuItemType = _menuItemType;
     generator.Partition = getCurrentPartition();
     generator.EncryptRequestQuery = true;

     requestQueryParameterCollection = generator.RequestQueryParameterCollection;
     requestQueryParameterCollection.UpdateOrAddEntry(_tableName, _fieldName,_fieldValue);

     System.Uri fullURI = generator.GenerateFullUrl();

     return fullURI.AbsoluteUri;
}

Thankyou

Send mail Through SMTP with Template

 In this blog we see how to send mail through SMTP by using template 

Step 1:-

  Code :-

  Map           templateTokens;

  templateTokens = new Map(Types::String, Types::String);     

   SysMailerSMTP           mailer = new SysMailerSMTP();

        try

        {

            switch (workflowContext.parmTableId())

            {

                case tablenum(LedgerJournaltable) :

                    SysMailerMessageBuilder builder = new SysMailerMessageBuilder(); 

                

                    SysEmailParameters      parameters = SysEmailParameters::find();

 

                    SysEmailMessageSystemTable  messageTable;

                    str envUrl = URLUtility::getUrl();

                    select messageTable

            where messageTable.EmailId == "Template name";


              

                    templateTokens.insert("envUrl",envUrl);

                    templateTokens.insert("Ledger journal table.JournalName",strFmt("%1",ledgerJournaltable.JournalName));  


                    if (parameters.SMTPRelayServerName)

                    {

                        mailer.smtpRelayServer(parameters.SMTPRelayServerName,


                                        parameters.SMTPPortNumber,


                                        parameters.SMTPUserName,


                                        SysEmailParameters::password(),


                                        parameters.SMTPUseNTLM,parameters.SMTPRequireSSL);

                    }

                    else

                    {

                        warning("ServerNotFound");

                    }

                    if (messageTable.EmailId)

                    {

                        builder.setFrom(parameters.SMTPUserName);

                        

                            builder.addTo(conPeek(con, i)).setSubject(strFmt("%1",messageTable.Subject + ledgerJournaltable.JournalNum)).setBody(SysEmailMessage::stringExpand(messageTable.Mail, SysEmailTable::htmlEncodeParameters(templateTokens)));

                         

                        SysMailerFactory::getNonInteractiveMailer().sendNonInteractive(builder.getMessage());

                        info('Mail successfully sent');

                    }

        }

     }

        catch (Exception::Error)

        {

            throw error("@SYS326780");

        }

    }

Step 2:-Configure template name in frontend 

Path:-

System administration > Setup > Email > System email templates

 


Thank you!!
Note:-Don't forget to configure SMTP details in front end and make sure done with Test connection

Monday, January 19, 2026

Debug In D365fo with Tier 2 environment database

 Today in this blog we will see how to debug in d365fo with Tier2 env's(uat,gc,preprod)

Step 1:-  Request JIT access 

If you have LCS access take JIT by providing IP of DEV Env  or else

Request from Admin We will get credentials in the format shown below


Servername/DBname

Username

Password

Step 2:- Turn off All Services like w3,worldwide,batches services 

Step 3:- Go to Folder from Filemanger K>AOSService\webroot as shown in image below and locate webconfig file

Step 5:- Copy the file and place it on desktop as back once debugging we need make back local DB

Step 6:- After that Right Click and open with latest visual studio(VS2022) as shown in below

Step 7:- After opening the file Press ctrlf and search AXDB and what ever credentials we got from LCS Replace with them as shown in below

Step 8:- After that for password ctrlf search for Password then change for Databaseacces.Sqlpwd as shown in below

Step 9:-  Save the changes and restart all  services and start debugging !!

Step 10:- Once you finish the process down the services and replace file and Turn on services to get back to normal


Thank You!!

Run some logic in workflow at particular step using WorkflowAutomatictask

 Scenario:- If you want to run some logic in workflow at particular we can use WorkflowAutomatictask Step1:- create a class   Code:-        ...