How to create a custom workflow in Dynamics 365 Finance and Operations

Table of Contents

Share this article:

Organizations using Dynamics 365 Finance and Operations often reach a point where standard processes no longer fit every approval, validation, or business exception. That is where workflow customization becomes valuable. A well-designed workflow helps teams standardize approvals, reduce manual follow-up, improve accountability, and keep business documents moving without unnecessary delays.

At its core, a workflow defines how a document or record progresses from one stage to another, who reviews it, what conditions apply, and what happens next. In Finance and Operations, this framework is used across many business scenarios such as procurement approvals, journal reviews, and exception handling. Microsoft’s workflow framework supports consistent process execution, visibility into status and history, and configurable workflow elements such as approvals, tasks, decisions, and line-item processing.

This guide explains what a workflow is, when custom development is needed, and how to build one in a practical and maintainable way.

What is workflow in Dynamics 365 Finance and Operations?

A workflow is both a technical framework and a business process model. From a business perspective, it controls how a document is submitted, reviewed, approved, rejected, or completed. From a technical perspective, it runs through the application framework and supports routing, conditions, actions, and status tracking.

This is why many teams rely on Dynamics 365 Finance and Operations workflow capabilities to bring structure to approvals that would otherwise be handled via email, spreadsheets, or manual follow-ups.

Why custom workflows matter

Out-of-the-box workflow coverage is useful, but it does not address every custom table, business event, or document type. When organizations build custom forms or extend existing processes, they often need approval logic that is not available by default.

That is where custom workflows become important. A custom implementation allows you to add business-specific logic, route approvals based on data, automatically update status values, and integrate approval actions directly into a custom form or an extended table.

For example, teams may need to create custom workflow in D365FO for:

  • custom journal scenarios
  • internal approval forms
  • specialized procurement requests
  • event approvals
  • internal compliance sign-offs
  • table extensions where no standard approval process exists

Common workflow scenarios in the real world

A workflow is not just about approval buttons. It is about operational control. Some practical Dynamics 365 workflow examples include:

  • approval of internally created event requests
  • movement journals needing manager review
  • fixed asset-related inventory processing
  • custom HR or administration forms
  • exception-based review for financial records
  • approvals triggered only when thresholds or conditions are met

These use cases show how workflows in Dynamics 365 can support both standard operations and highly tailored business processes.

Read more: Managing workflow participants in Dynamics 365 Finance and Operations using X++

Current best practice before you build

Before starting development, it is important to align with Microsoft’s current customization approach. In Finance and Operations apps, Microsoft recommends extensions rather than overlayering wherever possible, because extensions are easier to maintain and safer during updates.

That matters when you are building a custom workflow in Dynamics 365 Finance and Operations. If your scenario touches an existing Microsoft table or form, your design should favor event handlers, extensions, and metadata-driven configuration instead of directly modifying standard application objects.

You should also make sure the batch service is running before testing submission and processing, since workflow execution depends on it in many scenarios.

Key workflow components you need to create

When you create custom workflow in D365 Finance and Operations, the implementation usually includes the following technical pieces:

  1. A base enum for workflow status
  2. A table field to store status
  3. A query for the document or record
  4. A workflow category
  5. A workflow type
  6. A workflow approval element
  7. Event handlers and submit manager classes
  8. Form configuration to enable workflow actions

This is the foundation for setting up workflows in AX D365 when working with a new business document.

Types of workflow elements you should understand

Before building, it helps to know the main workflow components available in the framework. Microsoft supports elements such as approval processes, manual tasks, automated tasks, decisions, parallel branches, and line-item workflows. These elements allow both document-level and line-level routing depending on the business scenario.

That is why understanding the types of workflows in Dynamics 365 F&O is important before development begins. Not every process requires a fully custom solution. Sometimes, a standard approval structure with minor extension is enough.

Take control of your business operations

Discover how Confiz services can simplify your complex workflows and improve decision-making.

Get a Free Quote

Step-by-step: Creating custom workflows in Dynamics 365 Finance and Operations

Let’s consider a custom workflow example in Dynamics 365. Imagine you are building a form to input details about social events for an organization’s employees. The organizing team needs approval from a senior manager for these events, thus requiring a workflow linked to this form. To create this workflow, we will use the Inventory-to-Fixed Asset Journal form. Now, let’s consider the steps for creating a custom workflow in Dynamics 365 Finance and Operations for this scenario.

Note: Before proceeding with this Microsoft Dynamics 365 Finance and Operations workflow tutorial, ensure your MS Dynamics 365 Unified Operations Batch service is operational.

If the service is not running, follow these steps to start it:

To start the Microsoft Dynamics 365 Unified Operations Batch Service, follow these steps:

Start menu > type ‘Services’ > run Services (App) > find ‘Microsoft Dynamics 365 Unified Operations Batch Service’ > Properties > click on ‘Start.’

This article will guide you through each step of creating a custom workflow. We’ll create the following necessary elements in the Visual Studio project for this purpose:

1) Base Enum

2) Query

3) Workflow type

4) Workflow category

5) Workflow approval

After creating a workflow type and workflow approval, the corresponding Workflow classes and action menu item button will be automatically generated. Now let’s look into the next steps in detail.

Step 1. Create a workflow status enum

Start by creating a base enum that represents the record’s approval lifecycle, such as Draft, InReview, Approved, Rejected, or Cancelled. This status will be used throughout the form and workflow classes.

This is one of the first steps when learning how to create workflow in dynamics 365 for a custom business object.

Step 2. Add the status field to the table

Create a new field on your table and assign the enum to it. This field will persist the current state of the record.

If you are extending an existing Microsoft table, use extension-friendly patterns wherever possible instead of directly modifying the base object.

Step 3. Override submission logic

Override canSubmitToWorkflow() to define when a record is eligible for submission. A common approach is to allow submission only if the record exists and the current status is Draft.

This is a simple but essential control in any D365 workflow implementation because it prevents users from submitting incomplete or already processed records.

public boolean canSubmitToWorkflow(str _workflowType = ”)

{

boolean ret = false;

if(this.RecId != 0 && this.WFStatus == WorkflowStatus::Draft)

{

ret = true;

}

return ret;

}

Step 4. Add a method to update workflow state

Create a method such as UpdateWorkflowState() that updates the workflow status on the record. This method is typically called from event handlers as the workflow changes state.

For any workflow in D365 Finance and Operations, keeping status changes centralized in one reusable method makes the solution easier to maintain.

public static void UpdateWorkflowState(RefRecId _recId, WorkflowStatus _state)

{

EventDetails eventDetails;

;

select firstonly forupdate eventDetails

where eventDetails.RecId == _recId;

if (eventDetails !=null)

{

ttsBegin;

eventDetails.WFStatus = _state;

eventDetails.update();

ttsCommit;

}

}

Further readings: How to create custom services in Dynamics 365 Finance and Operations

Step 5. Create the query

Build an AOT query for the table and set Dynamic Fields to Yes. This query is used by the workflow type and gives the framework access to document data.

Step 6. Create the workflow category

Create a workflow category and assign the relevant module. The category determines where the workflow appears in configuration. Microsoft’s workflow type/category setup is still a core part of enabling a custom document for workflow in Finance and Operations apps.

This is also where many teams start shaping their broader Microsoft Dynamics workflow management design.

Step 7. Create the workflow type

Create the workflow type and assign:

  • category
  • query
  • document menu item
  • related properties required by the wizard

This step enables the document to appear in the workflow configuration interface.

If you are wondering how to create workflow in Dynamics 365 for a custom form, this is the point where the framework connection is established.

After finishing, you will see:

Step 8. Create the workflow approval element

Create a workflow approval tied to the type. Once created, the system generates several related classes and menu items that can be extended with your business logic.

This part of the framework is often where teams begin working with a Dynamic workflow designer experience in the configuration layer, even though the document support itself is technically built in Visual Studio.

This will create the following elements in your project. The usage of these elements will be explained later.

After clicking the Finish button, you will see these elements in your VS project.

Step 9: Update the submit manager class

The submit manager class controls what happens when a user submits or resubmits the record into the workflow. It initializes the workflow context, opens the submit dialog, activates the workflow, and refreshes the form after submission.

In this example, use the EventDeatilsWFTypeSubmitManager class for both submit and resubmit actions.

class EventDeatilsWFTypeSubmitManager

{

WorkflowSubmitDialog workFlowSubmitDialog;

RefRecId recordRecId;

WorkflowCorrelationId workFlowCorrelationId;

WorkflowComment note;

WorkflowVersionTable workflowVersionTable;

WorkflowWorkItemTable workflowWorkItemTable;

FormDataSource callerDS;

FormRun callerForm;

Common callerRecord;

boolean isSubmit;

public static void main(Args args)

{

EventDeatilsWFTypeSubmitManager submitManager =

new EventDeatilsWFTypeSubmitManager();

submitManager.run(args);

}

public void run(Args _args)

{

this.init(_args);

if (this.canSubmit())

{

if (isSubmit)

{

this.submit();

}

else

{

this.reSubmit(_args);

}

}

}

private void init(Args _args)

{

callerForm = _args.caller();

callerRecord = _args.record();

callerDS = FormDataUtil::getFormDataSource(callerRecord);

recordRecId = callerRecord.RecId;

workflowVersionTable = callerForm.getActiveWorkflowConfiguration();

workflowWorkItemTable = callerForm.getActiveWorkflowWorkItem();

workFlowSubmitDialog = WorkflowSubmitDialog::construct(workflowVersionTable);

isSubmit = this.isCalledFromSubmitMenuItem(_args.menuItemName());

}

private boolean isCalledFromSubmitMenuItem(str _menuItemName)

{

if (_menuItemName == ‘EventDeatilsWFTypeSubmitMenuItem’)

{

return true;

}

return false;

}

private boolean canSubmit()

{

boolean ret = true;

// Add additional validations here if required

return ret;

}

private void submit()

{

workFlowSubmitDialog = WorkflowSubmitDialog::construct(workflowVersionTable);

workFlowSubmitDialog.run();

note = workFlowSubmitDialog.parmWorkflowComment();

if (workFlowSubmitDialog.parmIsClosedOK())

{

try

{

ttsBegin;

workFlowCorrelationId =

Workflow::activateFromWorkflowConfigurationId(

workflowVersionTable.ConfigurationId,

recordRecId,

note,

false

);

ttsCommit;

this.refreshCallerWorkflowControls();

}

catch (Exception::Error)

{

throw error(“@SYS303438”);

}

}

}

private void reSubmit(Args _args)

{

WorkflowWorkItemActionManager workflowWorkItemActionManager =

new WorkflowWorkItemActionManager();

workflowWorkItemActionManager.parmArgs(_args);

workflowWorkItemActionManager.parmCaller(_args.caller());

workflowWorkItemActionManager.run();

if (workflowWorkItemActionManager.parmIsActionDialogClosedOK())

{

this.refreshCallerWorkflowControls();

}

}

private void refreshCallerWorkflowControls()

{

if (callerDS)

{

ttsBegin;

this.updateWorkflowState();

ttsCommit;

callerDS.reread();

callerDS.refresh();

}

callerForm.updateWorkflowControls();

}

private void updateWorkflowState()

{

switch (callerRecord.TableId)

{

case tableNum(EventDetails):

EventDetails::UpdateWorkflowState(

callerRecord.RecId,

WorkflowStatus::InReview

);

break;

}

}

public static EventDeatilsWFTypeSubmitManager constructWith(RefRecId _recId)

{

EventDeatilsWFTypeSubmitManager submitManager =

new EventDeatilsWFTypeSubmitManager();

submitManager.parmRecordRecId(_recId);

return submitManager;

}

public RefRecId parmRecordRecId(RefRecId _recordRecId = recordRecId)

{

recordRecId = _recordRecId;

return recordRecId;

}

}

Step 10: Add approval event handling logic

Next, update the approval event handler class. This class is responsible for changing the workflow status when approval-level actions occur, such as when the record is started, canceled, completed, or returned.

Use the following code in EventDetailsWFApprEventHandlerClass:

public void started(WorkflowElementEventArgs _workflowElementEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowElementEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::InReview

);

}

public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowElementEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::Cancelled

);

}

public void completed(WorkflowElementEventArgs _workflowElementEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowElementEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::Approved

);

}

public void returned(WorkflowElementEventArgs _workflowElementEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowElementEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::Rejected

);

}

Step 11: Add workflow type event handling logic

Now update the workflow type event handler. This class manages workflow-level events rather than approval-level events.

Paste the following code into EventDeatilsWFTypeEventHandler:

public void started(WorkflowEventArgs _workflowEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::InReview

);

}

public void canceled(WorkflowEventArgs _workflowEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::InReview

);

}

public void completed(WorkflowEventArgs _workflowEventArgs)

{

EventDetails::UpdateWorkflowState(

_workflowEventArgs.parmWorkflowContext().parmRecId(),

WorkflowStatus::Approved

);

}

public void denied(WorkflowElementEventArgs _workflowElementEventArgs)

{

// Add logic here if action is needed when workflow is denied

}

public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)

{

// Add logic here if action is needed when change is requested

}

public void created(WorkflowWorkItemsEventArgs _workflowWorkItemsEventArgs)

{

// Add logic here if action is needed when work items are created

}

Step 12: Add the approval element to the workflow type

Once the classes are ready, drag the workflow approval element into the Supported Elements node under the workflow type.

This links the approval step to the workflow definition and makes it available in workflow configuration.

Step 13: Rename the action menu item labels

Now update the labels of the generated action menu items so they are easier for users to understand in the interface.

For example, you can rename them to:

  • Submit
  • Resubmit
  • Cancel

This improves the usability of your workflow-enabled form.

Step 14: Assign the submit manager to the submit and resubmit actions

Open both of the following action menu items:

  • EventDetailsWFApprResubmitMenuItem
  • EventDeatilsWFTypeSubmitMenuItem

In the Object property, assign:

EventDeatilsWFTypeSubmitManager

Step 15: Assign the cancel manager

For the EventDeatilsWFTypeCancelMenuItem, set the Object property to:

WorkflowCancelManager

This enables the cancel action to work correctly through the standard workflow cancel manager.

Step 16: Enable workflow on the form

Now update your form properties so the workflow buttons appear correctly and the form becomes workflow-aware.

After building the project, the workflow type will appear in the relevant workflow configuration page, such as Procurement and Sourcing workflows, depending on the category you selected.

When you open that workflow type, the workflow configuration window will appear. Once configured and activated, the workflow will be added to the list and become available for use.

After that, open your form and you should see the workflow action button.

Extending workflow support for an OOTB table

If you want to enable workflow for an out-of-the-box Microsoft table, avoid overlayering. The recommended approach is to use extensions and event handlers.

Add post-handler logic for workflow submission

Use a post-handler on FormDataUtil.canSubmitToWorkflow() to control whether the standard record can be submitted.

[PostHandlerFor(classStr(FormDataUtil), staticMethodStr(FormDataUtil, canSubmitToWorkflow))]

public static void FormDataUtil_Post_canSubmitToWorkflow(XppPrePostArgs args)

{

Common record = args.getArg(identifierStr(_record));

HcmGoal hcmGoal = record as HcmGoal;

boolean ret = args.getReturnValue();

if (record.TableId == tableNum(HcmGoal))

{

if (hcmGoal.RecId != 0 &&

hcmGoal.HRHcmGoalWFStatus == HRHcmGoalWFStatus::Draft)

{

ret = true;

}

else

{

ret = false;

}

}

args.setReturnValue(ret);

}

Enable workflow on the standard form through an event handler

To avoid changing the base form directly, copy the data source OnInitialized logic into a class-level event handler.

For example:

[FormDataSourceEventHandler(formDataSourceStr(InventJournalMovement, InventJournalTable), FormDataSourceEventType::Initialized)]

public static void InventJournalTable_OnInitialized(FormDataSource sender, FormDataSourceEventArgs e)

{

sender.formRun().design().workflowEnabled(true);

sender.formRun().design().workflowDatasource(

formDataSourceStr(InventJournalMovement, InventJournalTable)

);

sender.formRun().design().workflowType(

workflowTypeStr(MovJournalWFType)

);

}

Add a workflow list page for modules that do not have one

In some modules, such as Inventory Management, you may not have a workflow form available by default.

In that case:

  1. Create a new Display menu item.
  2. Drag and drop it under the module menu.
  3. Set the Object Type to Form.
  4. Set the Object property to:

WorkflowTableListPageRnr

This allows the workflow types created for that module to appear in a workflow list page.

Result

Once everything is configured:

  • the workflow type appears in the workflow setup page
  • users can submit records directly from the form
  • status changes are reflected automatically
  • approve, reject, cancel, and resubmit actions behave correctly
  • standard tables can also be workflow-enabled using extensions instead of overlayering

What to validate before go-live

A technically working approval is not always a production-ready one. Before deployment, validate the following:

Security and role assignment

Make sure users have the correct roles to submit, approve, reject, and monitor records.

Batch processing

Confirm workflow batch jobs are running reliably in the target environment.

Status behavior

Validate every state transition, especially cancel, reject, and resubmit paths.

Notifications and escalation

Test what happens when approvers are unavailable or actions are delayed.

Upgrade safety

Review whether your implementation uses extension-safe patterns throughout.

This is where many D365 workflows fail in practice, not because the code is wrong, but because the operational design was incomplete.

Accelerate growth at an unprecedented pace

Discover how Confiz can help you take control of your daily operations, increasing growth and revenue.

Book a Free Consultation

Where custom workflow development adds the most value today

In today’s market, companies are not looking for workflow just for approval routing. They want cleaner auditability, fewer manual touches, better process visibility, and more structured control over exceptions. Microsoft’s workflow framework supports configurable elements, workflow history, and structured document processing, which makes it valuable for compliance-heavy and approval-driven operations.

That is why Dynamics 365 custom workflow activity work is often tied to digital transformation efforts rather than just technical customization.

A simple implementation example

Suppose your organization creates an internal event request form for employee activities. The organizer fills out details, submits the request, and a senior manager approves or rejects it. In this case, your workflow would:

  • create the record in Draft
  • allow submission only when mandatory details exist
  • move status to InReview on submit
  • notify the approver
  • move status to Approved, Rejected, or Cancelled based on action
  • allow resubmission if changes are requested

This is a practical example of workflow in D365 Finance and Operations aligned to a custom business form.

Summing up

The process is still conceptually similar to older AX-style workflow development, but the implementation approach should now be cleaner, more extension-friendly, and easier to support over time. Microsoft’s current workflow model continues to rely on workflow categories, workflow types, document queries, configurable elements, and activation through the workflow editor.

If your team is planning to create custom workflow, the smartest approach is to begin with the business process, define approval states clearly, and then map the technical artifacts around that process.

Whether you are building Microsoft Dynamics 365 Finance and Operations workflow support for a custom form, extending a standard table, or designing approval routing for a specialized scenario, success depends on both technical structure and business clarity.

At Confiz, we help organizations design scalable approval models, implement custom workflow activity Dynamics 365, and align technical workflow behavior with real business needs. If you are planning to create custom workflow initiatives in D365 F&O enhancements, or looking for help with D365 workflow architecture, reach out to us at marketing@confiz.com.

Take control of your business operations

Discover how Confiz services can simplify your complex workflows and improve decision-making.

Accelerate growth at an unprecedented pace

Discover how Confiz can help you take control of your daily operations, increasing growth and revenue.

About the author

Shahzada Phool Muhammad

Shahzada Phool Muhammad is a Software Engineer at Confiz and a technical consultant specializing in Microsoft Dynamics 365 Finance and Operations, as well as Microsoft Dynamics AX2012. With extensive expertise in these platforms, Shahzada supports businesses in optimizing their financial and operational processes.

New to implementation
guide?

Start here to understand how it’s reshaping the future of intelligent systems.

Subscribe

Get exclusive insights, curated resources and expert guidance.