Create a Simple Approval Workflow in Microsoft Dynamics D365
Step
1:
Basing on the requirement create a new base enum or use the existing
base enum
Step
2:
Create
new fields to your main table – Ex:
SMJ_PurchaseOrder
• Status – Enum Type - SMJ_Workflow
• SubmittedBy – Edt – UserId
• SubmittedDateTime – Edt – DateSubmitted
Set
the properties for the above 3 fields
AllowEditOnCreate – No
AllowEdit – No
Step
3:
Add table level methods
1.
Override the Method in the Main table–
canSubmitToWorkflow
2.
Create
a new method (Not overridden method) in the main table as below.
Below
is the code:
Override
the Method in the Main table– canSubmitToWorkflow
/// <returns></returns>
/// <returns></returns>
public boolean canSubmitToWorkflow(str _workflowType = '')
{
boolean ret;
SMJ_PurchaseOrder SMJ_PurchaseOrder;
select firstOnly SMJ_PurchaseOrder where SMJ_PurchaseOrder.PurchaseID == this.PurchaseID;
ret = this.RecId != 0 && this.WorkflowStatus == SMJ_Workflow::NotSubmitted &&
SMJ_PurchaseOrder;
//ret = super(_workflowType);
return ret;
}
Create a new method (Not overridden method) in the
main table as below:
public static void UpdateWorkflowState(RecId _recId, SMJ_Workflow _state)
{
SMJ_PurchaseOrder SMJ_PurchaseOrder = SMJ_PurchaseOrder::findByRecID(_recId,
true,ConcurrencyModel::Auto);
if(SMJ_PurchaseOrder)
{
ttsBegin;
SMJ_PurchaseOrder.WorkflowStatus = _state;
SMJ_PurchaseOrder.update();
ttsCommit;
}
}
Step
4:
Step
5:
Create workflow
category
Set the following properties for the “Work flow
category”
- Label – Give the label.
- Module – Select the module (in which module this workflow category belongs).
Step 6:
Create new workflow
Type.
In the wizard give the names like below
Name – (Name of the workflow type)
Category – ( the workflow category name which created
before).
Query – (Query name of this
wf)
Document Menu item – (Menu
item of the form where this wf is existing)
After we finish the wizard, it creates a
project with objects.
Then following 3 class and 2 menu items
automatically created.
Step
7:
Create a new workflow approval
Name
– (Name of the wf approval)
Workflow
document –(Name of the wf type which created above and ends
with Document).
Document
preview field group – filed group of the main table.(optional)
Document
Menu item – (Menu item of the forms where this wf is existing)
After we finish the
wizard, it creates a project with objects.
Then following class and menu item automatically created.
Step 8:
Step
9:
In the form design of
ListPage form and Details page form set the properties
example code
SubmitManager
Class:
/// <summary>
/// The JO_PurchWFTypeSubmitManager menu item action event
handler.
/// </summary>
public class JO_PurchWFTypeSubmitManager
{
SMJ_PurchaseOrder
PurchaseOrder;// IPMInvestmentMemorandumTable;
boolean
submit;
MenuItemName
menuItemName;
//
EPWorkflowControlContext
workflowControlContext;
WorkflowWorkItemTable
workflowWorkItemTable;
WorkflowComment
workflowComment;
WorkflowTypeName
workflowTemplateName;
WorkflowVersionTable
workflowConfigurationTable;
UserId
userId;
Object
SMJ_PurchaseOrder_ds;
#define.workflow('Purchase workflow')
public boolean dialogOk()
{
WorkflowSubmitDialog
workflowSubmitDialog;
WorkflowWorkItemActionDialog workflowWorkItemActionDialog;
boolean ok;
;
if (menuItemName == menuitemactionstr(JO_PurchWFTypeSubmitMenuItem))
{
workflowSubmitDialog = WorkflowSubmitDialog::construct(this.parmWorkflowConfigurationTable());
workflowSubmitDialog.run();
this.parmWorkflowComment(workflowSubmitDialog.parmWorkflowComment());
ok =
workflowSubmitDialog.parmIsClosedOK();
}
else if (menuItemName == menuitemactionstr(JO_PurchWFApprovalResubmitMenuItem))
{
workflowWorkItemActionDialog = WorkflowWorkItemActionDialog::construct(
workflowWorkItemTable,
WorkflowWorkItemActionType::Resubmit,
new MenuFunction(menuitemactionstr(JO_PurchWFApprovalResubmitMenuItem), MenuItemType::Action));
workflowWorkItemActionDialog.run();
this.parmWorkflowComment(workflowWorkItemActionDialog.parmWorkflowComment());
ok =
workflowWorkItemActionDialog.parmIsClosedOK();
userId =
workflowWorkItemActionDialog.parmTargetUser();
}
return ok;
}
public void init( Common _documentRecord,
MenuItemName _menuItemName,
WorkflowVersionTable
_workflowConfigurationTable,
WorkflowWorkItemTable
_workflowWorkItemTable)
{
this.parmSMJ_PurchaseOrderTable(_documentRecord);
this.parmSubmit(_menuItemName == menuitemactionstr (JO_PurchWFTypeSubmitMenuItem));
this.parmMenuItemName(_menuItemName);
this.parmWorkflowConfigurationTable(_workflowConfigurationTable);
this.parmWorkflowWorkItemtable(_workflowWorkItemTable);
this.parmWorkflowTemplateName (this.parmWorkflowConfigurationTable().WorkflowTable().TemplateName);
}
public SMJ_PurchaseOrder parmSMJ_PurchaseOrderTable(SMJ_PurchaseOrder _SMJ_PurchaseOrder = PurchaseOrder)
{
;
PurchaseOrder = _SMJ_PurchaseOrder;
return PurchaseOrder;
}
public MenuItemName parmMenuItemName(MenuItemName _menuItemName = menuItemName)
{
;
menuItemName = _menuItemName;
return menuItemName;
}
public boolean parmSubmit(boolean _submit = submit)
{
;
submit = _submit;
return submit;
}
public WorkflowComment parmWorkflowComment(WorkflowComment _workflowComment = workflowComment)
{
;
workflowComment = _workflowComment;
return workflowComment;
}
public WorkflowVersionTable parmWorkflowConfigurationTable(WorkflowVersionTable _workflowConfigurationTable = workflowConfigurationTable)
{
;
workflowConfigurationTable =
_workflowConfigurationTable;
return workflowConfigurationTable;
}
public WorkflowTypeName parmWorkflowTemplateName(WorkflowTypeName _workflowTemplateName = workflowTemplateName)
{
;
workflowTemplateName =
_workflowTemplateName;
return workflowTemplateName;
}
public WorkflowWorkItemTable parmWorkflowWorkItemtable(WorkflowWorkItemTable _workflowWorkItemTable = workflowWorkItemTable)
{
;
workflowWorkItemTable =
_workflowWorkItemTable;
return workflowWorkItemTable;
}
private void reSubmit()
{
NoYes
reSubmittingFromWeb;
// If we have a
workflow control context, we are being resubmitted from EP
//reSubmittingFromWeb
= this.parmWorkflowControlContext() == null ? NoYes::No : NoYes::Yes;
ttsbegin;
WorkflowWorkItemActionManager::dispatchWorkItemAction( workflowWorkItemTable, workflowComment,
userId, WorkflowWorkItemActionType::Resubmit, menuItemName);
SMJ_PurchaseOrder_ds =
PurchaseOrder.datasource();
PurchaseOrder = SMJ_PurchaseOrder::findByRecID(PurchaseOrder.RecId,
true, ConcurrencyModel::Auto);
PurchaseOrder.WorkflowStatus = SMJ_Workflow::Submitted;
PurchaseOrder.doUpdate();
if (SMJ_PurchaseOrder_ds)
{
SMJ_PurchaseOrder_ds.write();
SMJ_PurchaseOrder_ds.refresh();
}
ttscommit;
}
private void submit()
{
NoYes activatingFromWeb;
;
// If we have a
workflow control context, we are being activated from EP
// activatingFromWeb = this.parmWorkflowControlContext()
== null ? NoYes::No : NoYes::Yes;
ttsBegin;
Workflow::activateFromWorkflowType( this.parmWorkflowTemplateName(),PurchaseOrder.RecId, this.parmWorkflowComment(),activatingFromWeb,
curuserid());
SMJ_PurchaseOrder_ds =
PurchaseOrder.dataSource();
PurchaseOrder = SMJ_PurchaseOrder::findByRecID(PurchaseOrder.RecId,
true);
PurchaseOrder.SubmitedBy = curuserid();
PurchaseOrder.SubmittedDateTime =
utcDateTime2SystemDateTime(DateTimeUtil::utcNow());
PurchaseOrder.WorkflowStatus = SMJ_Workflow::Submitted;
PurchaseOrder.doUpdate();
if (SMJ_PurchaseOrder_ds)
{
SMJ_PurchaseOrder_ds.write();
SMJ_PurchaseOrder_ds.reread();
SMJ_PurchaseOrder_ds.refresh();
}
ttsCommit;
}
public static JO_PurchWFTypeSubmitManager construct()
{
return new JO_PurchWFTypeSubmitManager();
}
public static void main(Args args)
{
JO_PurchWFTypeSubmitManager JO_PurchWFTypeSubmitManager;
SMJ_PurchaseOrder
PurchaseOrder;
// Variable
declaration.
Object
callerDataSource;
// Hardcoded
workflow type name
//workflowTypeName
workflowTypeName = workflowtypestr(SMJ_Workflow);
// Initial note
is the information that users enter when they
// submit the
document for workflow.
WorkflowComment initialNote = "Enter any
comments";
;
PurchaseOrder = args.record();
JO_PurchWFTypeSubmitManager = JO_PurchWFTypeSubmitManager::construct();
if (args.menuItemName() == menuitemactionstr(JO_PurchWFTypeSubmitMenuItem) ||
args.menuItemName() == menuitemactionstr(JO_PurchWFApprovalResubmitMenuItem))
{
JO_PurchWFTypeSubmitManager.init(args.record(), args.menuItemName(),
args.caller().getActiveWorkflowConfiguration(),
args.caller().getActiveWorkflowWorkItem());
}
else
{
JO_PurchWFTypeSubmitManager.init(args.record(), args.menuItemName(), null, null);
}
if (JO_PurchWFTypeSubmitManager.dialogOk())
{
if (JO_PurchWFTypeSubmitManager.parmSubmit())
{
JO_PurchWFTypeSubmitManager.submit();
}
else
{
JO_PurchWFTypeSubmitManager.reSubmit();
}
if (args.menuItemName() == menuitemactionstr(JO_PurchWFTypeSubmitMenuItem) ||
args.menuItemName() == menuitemactionstr(JO_PurchWFApprovalResubmitMenuItem))
args.caller().updateWorkflowControls();
}
}
// public static void main(Args args)
//{
// //
TODO: Write code to execute once
a work item is submitted.
//}
}
EventHandler
for workflow type:
/// <summary>
/// The JO_PurchWFTypeEventHandler workflow event handler.
/// </summary>
public class JO_PurchWFTypeEventHandler implements WorkflowCanceledEventHandler,
WorkflowCompletedEventHandler,
WorkflowStartedEventHandler
{
public void started(WorkflowEventArgs _workflowEventArgs)
{
SMJ_PurchaseOrder::UpdateWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), SMJ_Workflow::Submitted);
}
public void canceled(WorkflowEventArgs _workflowEventArgs)
{
//
TODO: Write code to execute once the
workflow is canceled.
}
public void completed(WorkflowEventArgs _workflowEventArgs)
{
SMJ_PurchaseOrder::UpdateWorkflowState(_workflowEventArgs.parmWorkflowContext().parmRecId(), SMJ_Workflow::Approved);
}
}
EventHandler
class for workflow approval:
/// <summary>
/// The JO_PurchWFApprovalEventHandler workflow outcome event
handler.
/// </summary>
public final class JO_PurchWFApprovalEventHandler implements WorkflowElementCanceledEventHandler,
WorkflowElemChangeRequestedEventHandler,
WorkflowElementCompletedEventHandler,
WorkflowElementReturnedEventHandler,
WorkflowElementStartedEventHandler,
WorkflowElementDeniedEventHandler,
WorkflowWorkItemsCreatedEventHandler
{
public void started(WorkflowElementEventArgs _workflowElementEventArgs)
{
SMJ_PurchaseOrder::UpdateWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),SMJ_Workflow::Submitted);
}
public void canceled(WorkflowElementEventArgs _workflowElementEventArgs)
{
//
TODO: Write code to execute once the
workflow is canceled.
}
public void completed(WorkflowElementEventArgs _workflowElementEventArgs)
{
SMJ_PurchaseOrder::UpdateWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),SMJ_Workflow::Approved);
}
public void denied(WorkflowElementEventArgs _workflowElementEventArgs)
{
//
TODO: Write code to execute once the
workflow is denied.
}
public void changeRequested(WorkflowElementEventArgs _workflowElementEventArgs)
{
SMJ_PurchaseOrder::UpdateWorkflowState(_workflowElementEventArgs.parmWorkflowContext().parmRecId(),SMJ_Workflow::ChangeRequest);
}
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
//
TODO: Write code to execute once the
workflow is returned.
}
public void created(WorkflowWorkItemsEventArgs _workflowWorkItemsEventArgs)
{
//
TODO: Write code to execute once work
items are created.
}
}
Final
output:
Before
submit workflow
After submit workflow
Before
Approve workflow
After Approve workflow
Comments
Post a Comment