Custom workflow development in the Dynamics 365 Finance and Operations using x++ code
Syed Amir Ali
Microsoft Certified Dynamics 365 Finance & Operations Expert | MCT | Techno functional Supply Chain
Hi Reader, In this article, we will learn how to create a custom workflow and configure it in the dynamics 365 F&O apps to automate the process.
What is workflow?
A?workflow?in the dynamics 365 apps is a way that automate business processes without a user interaction. People usually use workflow processes to commence automation that doesn’t require any user involvement.
Let start learning by doing its practical.
Add a new base enum with name “CustomWorkflowBaseEnum”
Add the elements in the newly created enum by right click on the enum and select “Add Element”.
Add elements as shown in below figure and make sure submit element must be on top because when you are trying to create a record in the form. By default, first value will be selected on the flow.
Create a custom table with name “CustomWorkflowTable” and add three fields (Id, name, CustomWorkflowBaseEnum) in the table.
Add a field group in this table by right click on the field groups and click “New Group”.
Change the name the field group as “CustomWorkflowFieldGroup” and drag the fields in the field group according to your requirement. For learning perspective, I am drag and drop all the fields in the group.
Override CanSubmitToWorkflow method of this table
Add a new method with name "UpdateWorkflowStatus" in this table.
Write the below code in the above created methods.
public boolean canSubmitToWorkflow(str _workflowType = ''
??? {
??????? boolean ret;
???
??????? ret = super(_workflowType);
?
??????? if(this.CustomWorkflowBaseEnum != CustomWorkflowBaseEnum::Approved)
??????? {
?????????? ret = true;
??????? }
??????? else
??????? {
??????????? ret = false;
??????? }
???
??????? return ret;
??? }
?
??? public static void? updateWorkflowStatus(RefRecId recId , CustomWorkflowBaseEnum status)
??? {
??????? CustomWorkflowTable customWorkflowTable;
?
??????? ttsbegin;
?
??????? select forupdate customWorkflowTable
??????????? where customWorkflowTable.RecId == recId;
?
??????? customWorkflowTable.CustomWorkflowBaseEnum = status;
?
??????? customWorkflowTable.update();
?
??????? ttscommit;
?
??? })
Add a custom form with name “CustomWorkflowForm”
Add our custom table “CustomWorkflowTable” in the datasource of the form.
Set the form design pattern as "Custom".
Add the action pane and a grid and drag and drop the datasource fields in the grid.
Set allowEdit property of enum control in the grid to No.
Create a display menu item “CustomWorkflowMenu”.
Enter the created form name in the object property and set the label of the menu item.
Now create an extension of Accounts Receivable module in the project
Drag the menu item in the “InquiriesAndReport” section.
Create a new query with the name “CustomWorkflowQuery”
Add our table "CustomWorkflowTable" in the datasource of the query and set the dynamics field property to No.
Build the project with database synchronization.
Add work flow category “CustomWorkflowCategory”
Set module property to “SalesOrder” and also set the label.
Add a workflow type “CustomWorkflowType”
A new window will appear. ?Enter category name, query name, display menu item name.
Below classes and action menu items will automatically be created.
Change the label of workflow type submit action menu item.
Change the label of workflow type cancel action menu item
Add the below code in submit manager class.
/// <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.
?
??????? CustomWorkflowTable???? customWorkflowTable;
??????? WorkflowComment???????? note = "";
??????? WorkflowSubmitDialog??? workflowSubmitDialog;
??????? WorkflowCorrelationId?? workflowCorrelationId;
??????? WorkflowTypeName??????? workflowTypeName = workFlowTypeStr("CustomWorkflowType");
?
?
?
??????? //Opens the submit to workflow dialog.
?
workflowSubmitDialog =??? WorkflowSubmitDialog::construct(args.caller().getActiveWorkflowConfiguration());
?
??????? workflowSubmitDialog.run();
?
??????? if (workflowSubmitDialog.parmIsClosedOK())
??????? {
?
??????????? customWorkflowTable = args.record();
?
??????????? // Get comments from the submit to workflow dialog.
?
??????????? note = workflowSubmitDialog.parmWorkflowComment();
?
??????????? try
??????????? {
?
??????????????? ttsbegin;
?
workflowCorrelationId = Workflow::activateFromWorkflowType(workflowTypeName, customWorkflowTable.RecId, note, NoYes::No);
?
??????????????? customWorkflowTable.CustomWorkflowBaseEnum = CustomWorkflowBaseEnum::Submitted;
?
??????????????? customWorkflowTable.update();
?
??????????????? ttscommit;
?
??????????????? // Send an Infolog message.
?
??????????????? info("Submitted to workflow.");
??????????? }
?
??????????? catch (Exception::Error)
??????????? {
?
??????????????? error("Error on workflow activation.");
??????????? }
??????? }
?
??????? args.caller().updateWorkFlowControls();
?
?????? }
?
}>
Add the below code in workflow type event handler class
/// 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.
??????? CustomWorkflowTable::updateWorkflowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(),CustomWorkflowBaseEnum::Submitted);
?????? }
?
??? ?? public void canceled(WorkflowEventArgs _workflowEventArgs)
?????? {
???????????? // TODO:? Write code to execute once the workflow is canceled.
??????? CustomWorkflowTable::updateWorkflowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(),CustomWorkflowBaseEnum::Rejected);
?????? }
?
??? ?? public void completed(WorkflowEventArgs _workflowEventArgs)
?????? {
???????????? // TODO:? Write code to execute once the workflow is completed.
CustomWorkflowTable::updateWorkflowStatus(_workflowEventArgs.parmWorkflowContext().parmRecId(), CustomWorkflowBaseEnum::Approved);
?????? }
?
}
Change the Workflow Enable property to Yes and add workflow type name on the form design property.
Build the project with database synchronization.
领英推荐
Now add the workflow approval “CustomWorkflowApproval”
A window will appear.
Some classes and action menus created automatically.
Add the below code in workflow approval event handler class.
/// <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.
?????? }
?
??? ?? public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
?????? {
???????????? // TODO:? Write code to execute once the workflow is canceled.
??????? CustomWorkflowTable::updateWorkflowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), CustomWorkflowBaseEnum::Rejected);
?????? }
?
??? ?? public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
?????? {
???????????? // TODO:? Write code to execute once the workflow is completed.
??????? CustomWorkflowTable::updateWorkflowStatus(_workflowElementEventArgs.parmWorkflowContext().parmRecId(), CustomWorkflowBaseEnum::Rejected);
?????? }
}>
Change the label of workflow approval Approve Action Menu Item.
Change the label of workflow approval Delegate Action Menu Item
Change the label of workflow approval Reject Action Menu Item
Change the label of workflow approval RequestChange Action Menu Item
Change the label of workflow approval Resubmit Action Menu Item
Now open workflow type and right click on supported elements section and select “New Workflow Element Reference”
Enter workflow approval name in the Element Name property and also provide a name.
Change the label of workflow type.
Now build the project with database synchronization.
Open the form in d365 browser, see there is no workflow button enable. So, we need to configure the custom workflow in the attached module like we setup it in the Accounts Receivable module.
Go to Accounts Receivable module > Setup > Accounts receivable workflows. Click on the Accounts receivable workflows
Click on New button.
Select custom workflow type from the list (It’s the label of workflow type)
A new window will appear click on “Run” button.
A new form will open, enter email and password
If you are not logged in with admin account the below error will appear.
If you are logged in with admin account the below window will appear; Design the workflow according to your need.
Click on “Basic settings” and add placeholder.
Navigate to assignments and add select “User” option.
Click on “User” button and add user there.
Now click on “Basic Settings” Button under assignment window and provide placeholders.
Now drag workflow approval in the workflow window
Click on start and drag the connector (Arrow) to the workflow approval function.
Scroll the bar you will find end function.
Click on workflow approval and drag the connector (Arrow) to the end function.
Click “Save and close” button.
Click “OK” button and another form will open, click on “Activate” button there to activate the workflow.
Go back and now open the form again and you will see the workflow button visible there.
Happy Learning,
Syed Amir Ali.
Microsoft Dynamics 365 Techno-Functional Consultant | Finance & Operations | Business Central | Security | MCT | .NET Developer | Azure DevOps | Power Apps | Power Automate | Power BI
1 个月Alexio Simbarashe Pfumai
Software Developer
2 个月Thanks to you, I can create a workflow from scratch, thank you very much for your efforts, greetings from Turkey
Full Stack Web Developer | Creative FontEnd Developer | ASP.Net Core | Tech Trainer | SQL Server | ReactJS | LGU '23
3 个月tell me the importance of field group ?
IT manager at Response VietNam
9 个月hi is there any way to wrap it into an API then I can call it through another apps like ASP.NET ?
Dynamics 365 F&O Developer
1 年I followed this tutorial to a tee, but I still had one issue. I could submit my record to workflow but the submit button stayed in the workflow dropdown. The Cancel and View History buttons did not appear. I could also submit a record as many times as I wanted to, but the buttons did not switch. At last, I found that the issue was the canSubmitToWorkflow method. It was returning true after it had been submitted and thus did not allow the buttons to switch. Correction: Your canSubmitToWorkflow method should be the following: public boolean canSubmitToWorkflow(str _workflowType = '') ??{ ????boolean ret; ????ret = super(_workflowType); ????if(this.CustomWorkflowBaseEnum != CustomWorkflowBaseEnum::NotSubmitted) ????{ ??????ret = false; ????} ????else ????{ ??????ret = true; ????} ??? ????return ret; ??} The rest of the tutorial is great, thanks.