Approval Workflow Problem
When the out of the box SharePoint approval workflow publishes an item, it sets the “Modified by” field as “System Account” instead of setting this to the actual user who did the approval.
One way around this could be to add another column to hold the correct Modified by user instead of the out of the box Modified by column. But since not all clients will be satisfied with this approach, I will explain another way here.
The Solution
We will solve this problem by publishing the item with custom code instead of as part of the out-of-the-box SharePoint approval workflow process. But for our custom code to work, when creating the workflow association, we need to ensure the following:
- Leave the option – “Start this workflow to approve publishing a major version of an item” unselected.
- Leave the option – “Update the approval status after the workflow is completed (use this workflow to control content approval)” unselected too.
And now for the code…
We create a web scoped feature and add an event receiver to hold our code. Our event receiver will override the WorkflowCompleted method. As you may know, an Elements.xml file is automatically generated for us based on the settings we select when creating the event receiver.
For reference, here’s the Elements.xml code (Notice that the ListTemplateId is 100. The ListTemplateId specifies the index of the list template to which the event receiver applies. For a list of the default list template types, see SPListTemplateType).
<?xml version="1.0" encoding="utf-8"?> <Elements xmlns="http://schemas.microsoft.com/sharepoint/"> <Receivers ListTemplateId="100"> <Receiver> <Name>ApprovalEnhancementsWorkflowCompleted</Name> <Type>WorkflowCompleted</Type> <Assembly>$SharePoint.Project.AssemblyFullName$</Assembly> <Class>ApprovalEnhancements.ApprovalEnhancements.ApprovalEnhancements</Class> <SequenceNumber>10000</SequenceNumber> </Receiver> </Receivers> </Elements>
The C# Code
Here’s the full code for this fix. The entry point is the overridden WorkflowCompleted method.
using System; using System.Security.Permissions; using Microsoft.SharePoint; using Microsoft.SharePoint.Utilities; using Microsoft.SharePoint.Workflow; namespace ApprovalEnhancements.ApprovalEnhancements { /// <summary> /// List Workflow Events /// </summary> public class ApprovalEnhancements : SPWorkflowEventReceiver { private string editor = ""; /// <summary> /// A workflow was completed. /// </summary> public override void WorkflowCompleted(SPWorkflowEventProperties properties) { SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite(properties.WebUrl)) { using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl)) { SPListItem workflowHistoryItem = GetWorkflowHistoryItem(web, properties); if (workflowHistoryItem != null) { SPListItem item = GetItemForThisWorkflow(web, workflowHistoryItem, properties); editor = item[SPBuiltInFieldId.Editor].ToString(); } } } }); base.WorkflowCompleted(properties); PublishItemBasedOnWorkflowStatus(properties); } private SPListItem GetWorkflowHistoryItem(SPWeb web, SPWorkflowEventProperties properties) { string caml = string.Format(@"<Where> <And> <Eq> <FieldRef Name='WorkflowInstance' /> <Value Type='Text'>{0}</Value> </Eq> <Eq> <FieldRef Name='Event' /> <Value Type='WorkflowEventType'>2</Value> </Eq> </And> </Where>", properties.InstanceId.ToString("B")); SPList workflowHistory = web.Lists["Workflow History"]; SPQuery query = new SPQuery(); query.Query = caml; SPListItemCollection items = workflowHistory.GetItems(query); if (items.Count >= 1) { return items[0]; } return null; } private SPListItem GetItemForThisWorkflow(SPWeb web, SPListItem workflowHistoryItem, SPWorkflowEventProperties properties) { int itemId = Convert.ToInt32(workflowHistoryItem["ows_Item"].ToString()); Guid itemListGuid = new Guid(workflowHistoryItem["ows_List"].ToString()); SPList itemParentList = web.Lists[itemListGuid]; SPListItem item = itemParentList.GetItemById(itemId); return item; } private string GetStatusOfRuningWorkflow(SPListItem item, string workflowAssociationName) { SPWorkflow wf = item.Workflows[0]; // assume single workflow if (wf != null && wf.Tasks != null && wf.Tasks.Count > 0) { SPWorkflowTask task = wf.Tasks[wf.Tasks.Count - 1]; // analyze last task only if (task[SPBuiltInFieldId.TaskStatus].ToString() == "Completed") { string workflowOutcome = task[SPBuiltInFieldId.WorkflowOutcome].ToString(); if (workflowOutcome.IndexOf("Approved") >= 0) return "Approved"; else if (workflowOutcome.IndexOf("Rejected") >= 0) return "Rejected"; } return task[SPBuiltInFieldId.TaskStatus].ToString(); } return ""; } private void MarkItemApproveOrRejectBasedWorkflowStatus(SPListItem item, SPWeb web, string associationName, SPWorkflowEventProperties properties) { string status = GetStatusOfRuningWorkflow(item, associationName); //we are only interested in OUR WORKFLOW ASSOCIATION (i.e. configured in Settings List) //if it is different, then it returns empty string if (string.IsNullOrEmpty(status)) return; item.ModerationInformation.Status = SPModerationStatusType.Denied; if (status.Equals("Approved")) { item.ModerationInformation.Status = SPModerationStatusType.Approved; } item[SPBuiltInFieldId.Editor] = editor; item.UpdateOverwriteVersion(); if (status.Equals("Rejected")) { SPWorkflow wf = item.Workflows[0]; SPWorkflowTask task = wf.Tasks[wf.Tasks.Count - 1]; if (task["PercentComplete"].ToString() != "1") { task["Status"] = "Canceled"; task["PercentComplete"] = 1; web.AllowUnsafeUpdates = true; task.Update(); } SPWorkflowManager.CancelWorkflow(wf); } } private void PublishItemBasedOnWorkflowStatus(SPWorkflowEventProperties properties) { SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite site = new SPSite(properties.WebUrl)) { using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl)) { SPListItem workflowHistoryItem = GetWorkflowHistoryItem(web, properties); if (workflowHistoryItem == null) { return; } SPListItem item = GetItemForThisWorkflow(web, workflowHistoryItem, properties); //Provide association name so that it can ONLY approve item of that workflow string associationName = "Site Info Approval"; MarkItemApproveOrRejectBasedWorkflowStatus(item, web, associationName, properties); } } }); } } }
Leave a Reply