Professional Documents
Culture Documents
Sumit Loya
Table of Contents
1.
Introduction .................................................................................................................................. 3
1.1.1
1.1.2
1.1.3
1.1.4
1.2
1.2.1
Workflow Categories............................................................................................................. 5
1.2.2
1.2.3
Workflow Approvals............................................................................................................ 24
1.3.1
Table Modifications............................................................................................................. 32
1.3.2
1.3.3
Page | 2
1. Workflow Development
1.1 Introduction
A workflow is a depiction of a sequence of operations, declared as work of a person, a group of persons,
an organization of staff, or one or more simple or complex mechanisms. Workflow may be seen as any
abstraction of real work, segregated in work share, work split or other types of ordering.
Workflow is a module in Microsoft Dynamics AX 2009 that allows flexible task and approval routes for
documents created by users. For example, a purchase requisition may need to be approved by a number
of different employees according to the requisition's total amount, and each employee has to approve it
before the next employee in the approval route.
In this article, I am going to discuss about how to develop new workflow templates that can be
configured and implemented. By default Microsoft has provided following templates:
1.1.1 Accounts Payable workflow templates
The Accounts Payable module provides the following workflow templates.
Workflow template
Purchase requisition
approval
Vendor disbursement
template
Page | 3
note template
Vendor settle promissory
note template
Expense template
Page | 4
Allocations template
Daily template
Eliminations template
The sections that follow describe how we can create a new workflow.
Page | 5
workflow category as you can make use of available workflow categories. Following are the available
categories in AX 2009:
ExpenseManagement
LedgerJournalWFApprovalCustomer
LedgerJournalWFApprovalLedger
LedgerJournalWFApprovalVendor
PurchCategory
For our example we will be using an existing category PurchCategory. In case these categories are not
applicable to your scenario, you can go ahead and create new categories. To create new workflow
categories follow the procedure below:
1.
2.
3.
4.
5.
6.
Open AOT
Expand the Workflow node
Right-click on the Workflow Category node and select New Workflow Category.
A new workflow category called WorkflowCategory1 will be created.
Right-click on the newly created workflow category and select Properties
You can specify the following:
Property
Description
A unique name for the category
Name
A meaningful label for the category Ex: Purchase order
Label
Description about the category
Help Text
The module to which the category is applicable
Module
See the following screen shot:
Page | 6
Property
Name
Label
HelpText
Category
7. Save the newly created workflow template
Value
PurchOrderApproval
Purchase order approval
Use this template to create purchase order
approval workflows.
PurchCategory
Page | 7
Value
InventDim
InventDim
InnerJoin
Yes
Page | 8
Create a Class
1. In the AOT, right-click on the Classes node and select New Class
2. Create/Modify following methods in the new class and save it
Method
classDeclaration
checkContext
getQueryName
parmTotalAmount
parmTotalAmountExclTax
construct
Description
A validation method that checks the table using this class is
PurchTable only
Returns the name of the query as a string
Returns the total amount for the purchase order (A
corresponding field will be created in the workflow configuration
form for this method)
Returns the total amount excluding taxes for the purchase order
(A corresponding field will be created in the workflow
configuration form for this method)
Returns an instantiated instance of the class
Page | 9
Page | 10
Page | 11
Page | 12
= purchTable_ds.cursor();
= PurchReqWorkflowState::PendingCancellation;
purchTable_ds.write();
purchTable_ds.refresh();
}
}
After the class is ready create a new action type menu item for the class and attach it to the workflow
template. Do the following:
1. Open the AOT and Traverse to Menu Items Action
2. Create new Menu Item and set the following properties
Property
Name
Label
HelpText
Value
PurchOrderCancel
Cancel
Select the action Cancel to cancel the purchase
order after it has been submitted.
Class
PurchOrderWorkflowCancelManager
Called from
VendMisc
ObjectType
Object
RunOn
SecurityKey
3. Save the menu item
4. Now traverse to Workflow Workflow Templates PurchOrderApproval
5. Right-click and select Properties
6. Set the property CancelMenuItem to PurchOrderCancel
See the screen shot below:
Page | 13
Page | 14
Page | 15
PurchOrderComplete
Label
Help Text
ConfigurationKe
y
Document
PurchOrderDocument
DocumentFieldP
reviewGroup
StartedEventHa
ndler
Page | 16
CanceledEventH
andler
ParticipantProvi
der
DueDateProvide
r
HierarchyProvi
der
WorkflowUserGroupParticipa
ntProvider (This is the
standard participant provider.
You can extend this provider
and create your own provider
if needed.)
WorkflowWorkCalendarDueD
ateProvider (This is the
standard participant provider.
You can extend this provider
and create your own provider
if needed.)
WorkflowLimitHierarchyProvi
der (This is the standard
participant provider. You can
extend this provider and
create your own provider if
needed.)
ResubmitWebM
enuItem
ResubmitMenuI
tem
DelegateWebMe
nuItem
DelegateMenuIt
em
Page | 17
1. Open the AOT, traverse to Classes node and create a new class
2. Create following methods in the new class and save the class
class PurchOrderCompleteEventHandler implements
WorkflowElementCompletedEventHandler,
WorkflowElementCanceledEventHandler,
WorkflowElementReturnedEventHandler,
WorkflowElemChangeRequestedEventHandler,
WorkflowElementStartedEventHandler
{
}
public void canceled(WorkflowEventArgs _workflowEventArgs)
{
;
PurchTable::setWorkflowState(_workflowEventArgs.parmWorkflowContext().parm
RecId(), PurchReqWorkflowState::NotSubmitted);
}
public void completed(WorkflowEventArgs _workflowEventArgs)
{
;
PurchTable::setWorkflowState(_workflowEventArgs.parmWorkflowContext().parm
RecId(), PurchReqWorkflowState::WorkflowCompleted);
}
public void started(WorkflowEventArgs _workflowEventArgs)
{
;
PurchTable::setWorkflowState(_workflowEventArgs.parmWorkflowContext().parm
RecId(), PurchReqWorkflowState::Submitted);
}
public void changeRequested(WorkflowElementEventArgs
_workflowElementEventArgs)
{
;
PurchTable::setWorkflowState(_workflowElementEventArgs.parmWorkflowContext
().parmRecId(), PurchReqWorkflowState::ChangeRequest);
}
public void returned(WorkflowElementEventArgs _workflowElementEventArgs)
{
;
PurchTable::setWorkflowState(_workflowElementEventArgs.parmWorkflowContext
().parmRecId(), PurchReqWorkflowState::Returned);
}
Page | 18
Note: You may get error as the method setWorkflowState is not available. Refer to Table modifications
section to resolve this error.
3. Now traverse to Workflow Tasks PurchOrderComplete
4. Right-click and select Properties
5. Set the properties StartedEventHandler and CanceledEventHandler to
PurchOrderCompleteEventHandler
Now let us set the value for property DelegateMenuItem. For this property we need to create a new
action menu item. Follow the procedure below:
1.
2.
3.
4.
Property
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Value
PurchOrderDelegate
Delegate
Delegate purchase order to another.
Class
WorkflowWorkItemActionManager (You can create your own class
extending this class for specific features while delegating the workflow.)
Called from
VendMisc
Edit
Page | 19
5. Set this menu item as value for DelegateMenuItem property of PurchOrderComplete task
See the screen shot below showing the task we created in this section:
Page | 20
Value
Task Outcome: Complete
PurchOrderTaskComplete
Complete
Complete purchase order.
Class
WorkflowWorkItemActionManager
Called from
VendMisc
Edit
Task Outcome: Reject
PurchOrderTaskReject
Reject
Reject purchase order.
Class
WorkflowWorkItemActionManager
Called from
VendMisc
Edit
Task Outcome: RequestChange
PurchOrderTaskRequestChange
Request change
Send change request to submitter
Class
WorkflowWorkItemActionManager
Page | 21
RunOn
SecurityKey
NeededAccessLevel
See the screen shots below:
Called from
VendMisc
Edit
4. Once these menu items are created attach these menu items with task outcomes
5. Traverse to AOT Workflows Tasks PurchOrderComplete
6. Expand the Outcomes node and create three new outcomes with following properties
Page | 22
Property
Name
Type
Enabled
ActionMenuItem
EventHandler
Name
Type
Enabled
ActionMenuItem
EventHandler
Name
Type
Enabled
ActionMenuItem
EventHandler
Value
Task Outcome: Complete
Complete
Complete
Yes
PurchOrderTaskComplete
PurchOrderCompleteEventHandler
Task Outcome: Reject
Reject
Return
Yes
PurchOrderTaskReject
PurchOrderCompleteEventHandler
Task Outcome: RequestChange
RequestChange
RequestChange
Yes
PurchOrderTaskRequestChange
PurchOrderCompleteEventHandler
Page | 23
PurchOrderApproval
Page | 24
Label
Help Text
ConfigurationKe
y
Document
PurchOrderDocument
DocumentFieldP
reviewGroup
StartedEventHa
ndler
CanceledEventH
andler
ParticipantProvi
der
DueDateProvide
r
HierarchyProvi
der
Page | 25
needed.)
DocumentWebM The Web menu item that opens the workflow
enuItem
document form
DocumentMenuI The rich client menu item that opens the workflow
tem
document form
ResubmitWebM
enuItem
ResubmitMenuI
tem
DelegateWebMe
nuItem
DelegateMenuIt
em
PurchOrderDelegate (Created
in the task section. Refer task
section on how to create this
menu item)
Page | 26
Page | 27
Page | 28
Property
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Value
Approval Outcome: Approve
PurchOrderApprovalApprove
Approve
Approve purchase order.
Class
WorkflowWorkItemActionManager
Called from
VendMisc
Edit
Approval Outcome: Reject
PurchOrderApprovalReject
Reject
Reject purchase order.
Class
WorkflowWorkItemActionManager
Called from
VendMisc
Edit
Approval Outcome: RequestChange
PurchOrderApprovalRequestChange
Request change
Send change request to submitter
Class
WorkflowWorkItemActionManager
Called from
VendMisc
Edit
Page | 29
4. Once these menu items are created attach these menu items with task outcomes
5. Traverse to AOT Workflow Approvals PurchOrderApproval
6. Expand the Outcomes node and create three new outcomes with following properties
Property
Enabled
ActionMenuItem
EventHandler
Value
Approval Outcome: Approve
Yes
PurchOrderApprovalApprove
PurchOrderApprovalEventHandler
Approval Outcome: Deny
Page | 30
Enabled
ActionMenuItem
EventHandler
No
Yes
PurchOrderApprovalReject
PurchOrderApprovalEventHandler
Task Outcome: RequestChange
Yes
PurchOrderApprovalRequestChange
PurchOrderApprovalEventHandler
Page | 31
Page | 32
o
o
o
Note the fields SubmittedBy and SubmittedDateTime are not required to be created mandatorily but the
State field is necessary to perform different actions based on the status of the workflow.
Let us first go ahead and create the three fields. Do the following:
1. Open AOT
2. Traverse to Data Dictionary Tables PurchTable
3. Add three fields with following properties
Property
Value
Field : SubmittedBy
SubmittedBy
Name
No
AllowEditOnCreate
No
AllowEdit
PurchReqSubmittedBy
ExtendedDataType
Field : SubmittedDateTime
SubmittedDateTime
Name
No
AllowEditOnCreate
No
AllowEdit
PurchReqSubmittedDateTime
ExtendedDataType
Field : SubmittedDateTime
State
Name
No
AllowEditOnCreate
No
AllowEdit
PurchReqWorkflowState
EnumType
Next we create the methods mentioned earlier. Add the following methods along with this
implementation:
public boolean canSubmit()
{
PurchLine
purchLine;
boolean
ret = true;
;
ret = ret && (this.PurchStatus == PurchStatus::Received);
ret = ret && (this.State == PurchReqWorkflowState::NotSubmitted);
select firstonly RecId from purchLine where purchLine.PurchId ==
this.PurchId;
ret = ret && (purchLine.RecId != 0);
return ret;
}
Page | 33
Page | 34
Page | 35
= PurchTable::findRecId(_purchTableRecId, true);
= _purchReqWorkflowState;
switch (_purchReqWorkflowState)
{
case PurchReqWorkflowState::NotSubmitted:
purchTable.SubmittedBy
= '';
purchTable.SubmittedDateTime = DateTimeUtil::minValue();
break;
}
purchTable.update();
ttscommit;
}
Next we create a new field group. Do the following:
1. Open AOT
2. Traverse to Data Dictionary Tables PurchTable Field Groups
3. Add field group with Name = Workflow and Label = Workflow
4. Add following elements (fields) to the field group
a. State
b. SubmittedBy
c. SubmittedDateTime
d. requiredAction (method)
e. requiredActionDueDate (method)
f. mostRecentComment (method)
Modify PurchTableType class
This modification is only for our scenario. Traverse to Classes PurchTableType class
mayInvoiceBeUpdated method and copy following code before statement return ok;
ok = ok && (purchTable.State == PurchReqWorkflowState::WorkflowCompleted);
Page | 36
Open AOT
Traverse to Forms node and search for form PurchTable
Next expand PurchTable Designs node
Right-click on Design node and select Properties
Set property WorkflowEnabled to Yes
Set property WorkflowDatasource to PurchTable
Expand Design Group:Table Tab:TabHeader TabPage:TabHeaderOther
From the Data Sources section right-click on PurchTable and select Open New Window
Find field group Workflow; Drag it onto the TabPage:TabHeaderOther
Now expand the Form Methods node, override method canSubmitToWorkflow and add
following implementation
Description
Opens a dialog for submitting a purchase order
Initializes the submit class
Set/Get method for Menu Item Name
Set/Get method for PurchTable record
Set / Get method for Submit variable
Page | 37
parmWorkflowComment
parmWorkflowConfigurationTable
parmWorkflowControlContext
parmWorkflowTemplateName
reSubmit
submit
construct
main
purchTable;
workflowConfigurationTable;
workflowComment;
submit;
workflowWorkItemTable;
userId;
menuItemName;
workflowControlContext;
workflowTemplateName;
Page | 38
Page | 39
workflowSubmitDialog;
workflowWorkItemActionDialog;
ok;
if (menuItemName == menuitemactionstr(PurchOrderSubmitToWorkflow))
{
workflowSubmitDialog =
WorkflowSubmitDialog::construct(this.parmWorkflowConfigurationTable());
workflowSubmitDialog.run();
this.parmWorkflowComment(workflowSubmitDialog.parmWorkflowComment());
ok = workflowSubmitDialog.parmIsClosedOK();
}
else if (menuItemName == menuitemactionstr(PurchOrderReSubmit))
{
workflowWorkItemActionDialog =
WorkflowWorkItemActionDialog::construct( workflowWorkItemTable,
WorkflowWorkItemActionType::Resubmit,
new MenuFunction(menuitemactionstr(PurchOrderReSubmit),
MenuItemType::Action));
workflowWorkItemActionDialog.run();
this.parmWorkflowComment(workflowWorkItemActionDialog.parmWorkflowComment()
);
ok = workflowWorkItemActionDialog.parmIsClosedOK();
userId = workflowWorkItemActionDialog.parmTargetUser();
}
return ok;
}
public static PurchOrderWorkflow construct()
{
return new PurchOrderWorkflow();
}
Page | 40
Common
_documentRecord,
MenuItemName
_menuItemName,
WorkflowConfigurationTable
_workflowConfigurationTable,
WorkflowWorkItemTable
_workflowWorkItemTable,
EPWorkflowControlContext
_workflowControlContext
)
{
this.parmPurchTable(_documentRecord);
this.parmSubmit(_menuItemName == menuitemactionstr
(PurchOrderSubmitToWorkflow));
this.parmMenuItemName(_menuItemName);
if (_workflowControlContext)
{
this.parmWorkflowControlContext(_workflowControlContext);
this.parmWorkflowWorkItemtable
(_workflowControlContext.getActiveWorkflowWorkItem());
this.parmWorkflowComment(_workflowControlContext.getWorkflowComment());
this.parmWorkflowTemplateName
(_workflowControlContext.getActiveWorkflowConfiguration().TemplateName);
}
else
{
this.parmWorkflowConfigurationTable(_workflowConfigurationTable);
this.parmWorkflowWorkItemtable(_workflowWorkItemTable);
this.parmWorkflowTemplateName
(this.parmWorkflowConfigurationTable().TemplateName);
}
}
Page | 41
void reSubmit()
{
Object
purchTable_ds;
;
ttsbegin;
WorkflowWorkItemActionManager::dispatchWorkItemAction(
workflowWorkItemTable, workflowComment, userId,
WorkflowWorkItemActionType::Resubmit, menuItemName, false);
purchTable_ds
purchTable.State
= purchTable.dataSource();
= PurchReqWorkflowState::Submitted;
if (purchTable_ds)
{
purchTable_ds.write();
purchTable_ds.refresh();
}
ttscommit;
}
void submit()
{
Object
NoYes
;
purchTable_ds;
activatingFromWeb;
=
=
=
=
purchTable.dataSource();
curuserid();
DateTimeUtil::utcNow();
PurchReqWorkflowState::Submitted;
if (purchTable_ds)
{
purchTable_ds.write();
purchTable_ds.refresh();
}
}
Page | 42
Page | 43
Property
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Name
Label
HelpText
ObjectType
Object
RunOn
SecurityKey
NeededAccessLevel
Value
Menu Item: Submit
PurchOrderSubmitToWorkflow
Submit
Submit purchase order workflow
Class
PurchOrderWorkflow
Called from
VendMisc
Edit
Menu Item: Resubmit
PurchOrderApprovalReject
Submit
Resubmit purchase order workflow
Class
PurchOrderWorkflow
Called from
VendMisc
Edit
Next we will attach these menu items with workflow templates and approvals / tasks
Attach Submit Action Menu Item to Workflow Template
1. Open the AOT
2. Traverse to Workflow Workflow Templates
3. Find PurchOrderApproval template and set the property SubmitToWorkflowMenuItem as
PurchOrderSubmitToWorkflow
4. Save the template
See the screen shot below:
Page | 44
Page | 45
Now the new workflow template is created and ready for configuration. Unless you create one active
configuration for this workflow, the Submit button will not be visible on the purchase order form.
To know more about configuring workflows click here.
Page | 46