In the first part of this series we walked through the steps to create a workflow type constant, add workflow support to tables, add records that define the workflow type, and add records to the Workflow Condition Editor content.  This article will walk you through finishing your workflow project by guiding you through adding code to enable workflow actions on windows for users.

Step 5: Add code for workflow actions from windows.

If you’ve made it to this step, you now have all of the supporting records set up in order for the workflow engine to recognize your workflow. Now we need to make the modifications to the resources in the dictionary that house the business object your workflow is based on. We will continue with our Item workflow example.

Step 5 is really broken into nine separate steps as follows:

a. Add Workflow_Document_Steps table to form

b. Add InfoBar_Initialize form procedure to form

c. Add code to clean up InfoBar triggers on form post script

d. Add 3 workflow buttons to main window

e. Add ‘Workflow Status’ field, hidden, to the main window

f. Add entry to SetWFBusObjKeyforWorkflowType() of form wfEngine for new Workflow Type, or create trigger against this for 3rd party dictionary workflow

g. Add form procedure to call to WFDisplayDocumentInfo of form wfEngine

h. Set up workflow and steps in product

i. Add support for email notifications

Step 5a: Add Workflow_Document_Steps table to form:

 

On the form that houses your business object, add the Workflow_Document_Steps table. This table will house the available workflow action steps the current user will need to perform on a particular business object displayed on the form.

Step 5b: Add InfoBar_Initialize form procedure to form

On this same form, create a new form procedure titled “InfoBar_Initialize”. It must be named this or the Dexterity engine will not recognize it as specific to workflow.

The “InfoBar” is a new dexterity control created specifically for Workflow 2.0, but it has the potential to be used by other features. The InfoBar is basically a strip of space at the top of a Dexterity window that can be populated with a variety of controls and text. For Workflow, we will be populating it with some informational text and button controls.

 

The following code example is all this form procedure should contain:

in integer product_id;
in integer form_id;
in integer window_id;

call Workflow_Infobar_Initialize, product_id, form_id, window_id, <WORKFLOW_TYPE_CONSTANT>, false;

The only thing you would need to change from this code example is the name of the Workflow Type Constant to your own constant, which you should have created in Step 1.

Step 5c: Add code to clean up InfoBar triggers on form post script.

Calling Workflow_Infobar_Initialize inside the InfoBar_Initialize form script in the previous step creates objects on the infobar that are executed using dexterity triggers. If you close the window the Infobar was created on, you will want to remove all of the triggers that were created. To do this, add the following code to your form post script, changing the form reference (IV_Item_Maintenance) to the form your workflow business object originates from:

local integer formid, trigger_tag, i;



formid=resourceid(form IV_Item_Maintenance);


i=countitems('(L) InfoBar_Trigger_Tags' of window 'Dummy Window' of form 'Main Menu');


while i>0 do

if itemname('(L) InfoBar_Trigger_Tags' of window 'Dummy Window' of form 'Main Menu',i)=str(formid) then


            trigger_tag=integer(itemdata('(L) InfoBar_Trigger_Tags' of window 'Dummy Window' of form 'Main Menu',i));


            Trigger_Unregister(trigger_tag);


            delete item i from '(L) InfoBar_Trigger_Tags' of window 'Dummy Window' of form 'Main Menu';


      end if;

      decrement i;


end while;  

Step 5d: Add 3 workflow buttons to main window.

When you open up your window on the form you wish to perform workflow actions on, you will want to add 3 buttons to your main window. The 3 button should be available to you from the list of global fields available to all users:

1. Workflow Button

2. Workflow Single Action Button

3. Workflow View History Button

Please note, the Workflow Button and Workflow Single Action Button should overlap.

Also, be sure to set the ‘SetChangeFlag’ property of the “Workflow Button” to FALSE.

The Workflow Engine will determine what workflow actions are available to the current user for the current business object displayed. For example, if the user only has the ability to Submit, then the Workflow Single Action Button is enabled while the Workflow Button is disabled. This is all done in the background, as the user should not have to write any code to disable/enable any of these workflow buttons.

 

Step 5e: Add ‘Workflow Status’ field to the main window.

You will then need to add the global ‘Workflow Status’ field onto your main window. Make sure the ‘Visible’ property is set to FALSE, and the ‘Editable’ property is set to FALSE.

 

Step 5f: Add entry to SetWFBusObjKeyforWorkflowType() function of form wfEngine for new Workflow Type, or create trigger against this for 3rd party dictionary workflow

You are finished making modifications to your main form, you can close that form down and save your changes.

You will now need to add code to the wfEngine form, or create some triggers, based upon if you are adding a workflow to the core dictionary or not.

For a workflow in the core dictionary, you will need to add an entry to the SetWFBusObjKeyforWorkflowType() form function of form wfEngine.

in [WORKFLOW_TYPE_ITEM_APPROVAL]

            set sBusObjKey to l_field_1;

 

For our Item Workflow example, you would just add the preceding 2 lines of code to the case statement inside the SetWFBusObjKeyforWorkflowType() form function.

3rd party workflows require a 2-step process:

1. Create a trigger to set the Workflow Business Object Key

2. Register the trigger you created.

An example of the trigger Registration:

l_result = Trigger_RegisterFunction(function SetWFBusObjKeyforWorkflowType of form wfEngine, TRIGGER_AFTER_ORIGINAL, function Set3rdPartyKey);
	if l_result <> SY_NOERR then
		warning "Function trigger registration failed.";
	end if;


The actual Set3rdPartyKey global function:

function returns 'Workflow Business Object Key' sBusObjKey;
in 'Workflow Type Name' l_wf_type_name;
in anonymous l_field_1;
optional in anonymous l_field_2;
optional in anonymous l_field_3;
optional in anonymous l_field_4;
if sBusObjKey = "" then
	if l_wf_type_name = WORKFLOW_TYPE_XXXX_APPROVAL then
	{Set the single-field key for the Lead object}
		set sBusObjKey to l_field_1;
	end if;
end if;

If the primary key for your business object has more than one field, you would append the string representation of each field together, separated by the tilde(~) character. An example if you have 3 fields in your primary key:

set sBusObjKey to l_field_1+CH_TILDE+str(l_field_2)+CH_TILDE+str(l_field_3)


If your field is already a string, you won’t have to use the str() casting function. You can also use the global constant CH_TILDE for readability purposes.

Step 5g: Add form procedure to call to WFDisplayDocumentInfo of form wfEngine

Now that everything is all set up, you will need some sort of mechanism to display your document’s workflow status and information.   To facilitate this, you will want to add a DisplayWorkflowInfo form procedure to the form that houses your document workflow, in our example, it would be the IV_Item_Maintenance form. Once this procedure is created, you would create a call to your new WFDisplayDocumentInfo form procedure from whatever script you use to display your current record’s information (typically, it would be your “Display Existing Record” script).

Here is an example of this form procedure, continuing with our Item Workflow example, note that the in parameter for Item Number, the product ID, form and Workflow Type Constant are all that needs to change:

DisplayWorkflowInfo of form IV_Item_Maintenance

in 'Item Number’	sItemNumber;
in boolean	l_first_class_window;
in table	Workflow_Document_Steps;
 
local integer l_product_id;
l_product_id=0; {The dictionary ID of the dictionary that contains the form you are working on}
call WFDisplayDocumentInfo of form wfEngine,	
l_product_id, Resource_GetID(l_product_id,DT_FORM,technicalname(form IV_Item_Maintenance)), 
1{Window ID}, {
WORKFLOW_TYPE_ITEM_APPROVAL, {Constant that defines your workflow type}
sItemNumber,	{first field in the key that guarantees uniqueness of this document}
     l_first_class_window,
     false, {IV_Item_Maintenance is not an inquiry window}
     table Workflow_Document_Steps; {up to 3 optional fields after here are possible}

 

So, in your “Display Existing Record” script (typically at the end of this script), you would call your new form procedure like so:

call DisplayWorkflowInfo of form IV_Item_Maintenance,'Item Number',true,
table Workflow_Document_Steps;


***Note in the above call, we reference table Workflow_Document_Steps, which is the table we added back in step 5a.


Step 5h: Set up workflow and steps in Workflow Maintenance window

Congratulations! You have now set up everything sanscript-wise to enable your new Workflow type! All that remains now to do is to open up the Workflow Maintenance window and start setting up workflows based on your new workflow type.

 

When you log into Dynamics GP and navigate to the Workflow Maintenance window (Tools>>Setup>>Company>>Workflow>>Workflow Maintenance), you should now see your new workflow type appear in the treeview window on the left side of your screen. You might need to choose the appropriate Series in the Series drop-down-list in order to see your new workflow type.