Download Demo Solution
Out-of-the-box SharePoint Approval workflows can issue notifications when a task hasn't been completed on time, but State Machine Workflows aren't as developer-friendly and take some additional logic to generate re-notification tasks. This can become even more complex if the particular state issues tasks in parallel to multiple users, who may complete their task at different times, and should not be expected to approve or reject the same task more than once. Also, users may get used to responding to tasks from Outlook by using the Open This Task icon found in the task message ribbon bar; re-notification emails can confuse them.
The approach described here supports these requirements within a single state, and an example solution is provided as a starter.
The key to re-notifications is to break the state into three distinct phases:
- Event handling
- Delay and looping
The StateInitialization component is often added to a state to prepare variables needed for the state and to create the state's tasks. In most cases, this is only run once; however, re-notifying users of their incomplete tasks with new tasks requires looping through the state multiple times, so IfElse condition tests must be used to contain a Code control for first run initialization and for EACH CreateTask control so that tasks aren't issued unnecessarily.
The image to the right illustrates this. The first IfElse condition determines if this is the state's first run, and sets variables used later throughout the entire workflow. In this example, up to three users may need separate approval tasks, and the variables set here guide the IfElse conditions below which create the tasks.
If tasks are completed they will no longer need issued at each loop, so the declarative conditions look like this:
this._User1TaskRequired && !this._User1TaskCompleted
IMPORTANT: Each task will have a unique token and will create a unique task GUID. The unique tokens are used in Event Handling, and the unique task id is used to delete the task in the Delay and Looping phase.
Finally, an IfElse statement is included to reject any request that never had approvers.
Responding to potentially three tasks requires three separate OnTaskChanged event components, and each needs to test if the task was rejected, if ALL needed tasks are complete, or if the task was approved but others users have yet to respond.
The EvenDriven block opens with the green OnTaskChanged control, which in this case reads the original item to see if a checkbox has been selected indicating approval.
The blue completeTaskUser1 control uses the same token used when that user's task was created, and is bound to a common method shared by all completeTask controls.
The gray codeCompleteUser1 control sets some important variables:
_User1TaskOpen = false;
_User1TaskCompleted = true;
The first will prevent the Delay and Looping phase from attempting to delete a non-existent task. The second prevents the Inititialization phase from re-issuing a completed task. And the third decrements a counter used in the IfElse condition to the left. When this counter = zero, all tasks are completed; if all are approved, the workflow advances to the Approved state.
This phase starts with a delay control, and then deletes any open tasks in series. One EventDriven component contains the logic for all the tasks.
IMPORTANT: Do not create separate EventDriven components for each potential task. This leads to serious logic issues when multiple delays loop back to the start of the state.
The brick delayGetApprovalsRenotify control will wait for the specified time before proceeding. A method has been included in the solution that can help prevent tasks being sent over weekends.
IMPORTANT: When using Delays in State Machine Workflows, the SharePoint 2010 Timer Service MUST be reset after the workflow is bound to a list. The code for this has been included with the demo solution in the "DemoNotification Step 2 – Workflow" event receiver, but can be reset manually on the server with the Server Manager application.
The gray codeGetApprovalsRenotify Code control sets a variable used as a prefix in the task titles. Any task created after this point will have a prefix in the title:
_GetApprovalReminderPrefix = "REMINDER: ";
The existence of each potential task is tested by its own IfElse condition, and then DELETED using the task GUID created during Initialization. Deleting these tasks helps clean up the web workflow details page, but also means that multiple tasks will be sent to users that don't respond.
Users should be informed of this and taught to complete the LAST task email sent. Outlook won't remove old tasks from their inbox, and each task will have a unique list item id, so older tasks are no longer relevant.
The grey Code controls resets the variable used by the IfElse condition for each task
Finally, after all this cleanup, the phase loops back to the start of the state, sending out new tasks as needed. No approval tests should be run in the Delay and Looping phase, the OnTaskChanged events should handle that exclusively. This also prevents logic errors.
A working solution
Download Demo Solution
The demo re-notification state machine diagram is laid out below. The stateGetApprovals state contains the main re-notification logic and can stand on its own, but additional stateRejected and stateApproved states are a good practice to follow.
As a demonstration, the Rejected state also issues a task to the originator, allowing an item to be resubmitted. This Rejected state will add an additional prefix to the task titles indicating that is has been resubmitted if the originator chooses to resubmit.
The solution creates a simple WorkList list during setup ("DemoRenotification Step 1 – Setup" feature) that simulates a request approval process. Users that are members of the site will receive task notifications, but first they must "approve" their appropriate checkbox in the original request item in WorkList:
After the user selects their checkbox (or doesn't), they can then complete their task. This simulates a process where users update the original item before approving their task.
(Tasks themselves can be designed to gather data, but this requires Content Types be added to the Tasks list and is not demonstrated here.)
During the Rejected state, the originator can open the WorkList item and choose the Resubmit checkbox before completing the task to trigger another round of approvals. This solution resets all pertinent values to demonstrate a clean re-submit/approval process.
The solution can deploy directly to a site, or can be triggered by features. A basic Team Site can be used, but it's necessary to set up the (hidden) Workflows History list. This is easily done by creating an OOTB workflow on any list in the site, which will set up the hidden list for you. You can then test for it in the browser:
After the solution is added, trigger the features in order, first the web feature "DemoRenotification Step 1 – Setup", then the site collection feature "DemoRenotification Step 2 – Workflow".
Remember to add users to your site's permission groups if you want to send email tasks.