Workflow Implementation


Introduction to current workflow module implementation


Five database tables are involved. Three of them are used to define a document process flow. The other two are used to track the history of process flow of each instance of a document. Document is an object that has multiple statuses through out its life span in the system.


Three of the database tables used to define document workflow are:


⦁ Process Template: is the table that holds the name, description and graphical representation of the whole workflow for a specific kind of document.


⦁ State Template: holds the states that the specific kind of document goes through. Example: Draft, Apprved, Rejected, Closed, etc... Here "StateNo" shows the sequence of the states. And "StateType" shows which state is the intial one, zero represents the initial state and the others states will be represented by number one. "AllowedAccessLevel" was probably meant to be used in user permission but we don't need to use it now. "ParentProcessTemplateID" as its name suggestes, it relates the states with their parent process template.


Flow Template: is the table that holds the definition of each path that the specific document pass through. A single entry on this table consists of two states the initial state and the final state. And it also has "ParentProcessTemplateID" which relates the flows with their parent process template.


Two of the database tables used to track the status history of each entry of the document are:


⦁ BusinessProcess: links the document to its workflow defition. It holds the document ID and Name. It also holds the current state of a document entry.


⦁ BusinessProcessState: holds the state history of an instance of a document. It holds all the information of a document entry at a specific state. It holds the stateID, the "PerformedBy", the "DatePerformed", the "Comment" left and a file attached by the performer.


How to implement workflow on a document


Step 1: Manually add a workflow definition for the document on the three database tables mentioned above. And link that entry on the "ProcessTemplate" table to the document table. And backup an sql file containing all the changes made to the database.


Step 2: Update the model and mapping for both the document and the "BusinessProcess"


Step 3: On the document create method add this sub-code:


// Add  new row on applicationsetting table in database and service for the document workflow named 

get[DOCUMENTNAME]Workflow


int BP_PR = _applicationSettingService.get[DOCUMENTNAME]Workflow();


// Check if BP_PR is not null
BusinessProcessState createdstate = new BusinessProcessState
{
DatePerformed = DateTime.Now,
PerformedBy = User.Identity.Name,
Comment = "A [DOCUMENT_NAME] is Created"
};


BusinessProcess bp = _businessProcessService.CreateBusinessProcess(BP_PR, 0, "[DOCUMENT_NAME]", createdstate);


And use the "bp.BusinessProcessID" to set the "BusinessProcessID" on the document object to be persisted.


Step 4: Define a "Promote_Workflow" Action on the document controller like this:


[HttpPost]
public ActionResult Promote(BusinessProcessStateViewModel st, int? statusId)
{


var fileName = "";
if (st.AttachmentFile.HasFile())
{
//save the file
fileName = st.AttachmentFile.FileName;
var path = Path.Combine(Server.MapPath("~/Content/Attachment/"), fileName);
if (System.IO.File.Exists(path))
{
var indexOfDot = fileName.IndexOf(".", StringComparison.Ordinal);
fileName = fileName.Insert(indexOfDot-1, GetRandomAlphaNumeric(6));
path = Path.Combine(Server.MapPath("~/Content/Attachment/"), fileName);
}
st.AttachmentFile.SaveAs(path);
}


var businessProcessState = new BusinessProcessState()
{
StateID = st.StateID,
PerformedBy = HttpContext.User.Identity.Name,
DatePerformed = DateTime.Now,
Comment = st.Comment,
AttachmentFile = fileName,
ParentBusinessProcessID = st.ParentBusinessProcessID
};


_businessProcessService.PromotWorkflow(businessProcessState);


if(statusId!=null)
           return RedirectToAction("DOCUMENT_ACTION", "DOCUMENT_CONTROLLER", new { Area = "EarlyWarning", statusId });


return RedirectToAction("Index", "DOCUMENT_CONTROLLER", new { Area = "DOCUMENT_AREA" });
}

 

Step 5: Here is how to add the workflow dropdown that will hold all the actions that are currently available to the document:


<div class="btn-group">
<button type="button" id="action_@index" class="btn btn-default dropdown-toggle btn-xs green-stripe" data-toggle="dropdown">
<i class="fa fa-ellipsis-horizontal"></i> @Html.Translate("Workflow") <i class="fa fa-angle-down"></i>
</button>
<ul class="dropdown-menu pull-right">
@foreach (FlowTemplate actions in state.InitialStateFlowTemplates)
{
if (UserAccountHelper.EarlyWarningPsnpOperationCheck(EarlyWarningConstants.Operation.Approve_Need_Assessment) && actions.Name == "Approve")
{
<li class="edit_button"><a href="javascript:promot_workflow(@item.BusinessProcessID ,@actions.FinalStateID,'@actions.Name',@item.PlanID)" title="@actions.Name">@actions.Name</a></li>
}
}
<li class="divider"></li>
<li class="edit_button"><a href="javascript:workflow_history(@item.BusinessProcessID)"> History </a></li>
</ul>
</div>


Step 6: Add the partial modal view that displays the form of promoting a workflow

<div id="modalHistory" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="false">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
<h4 id="modalHistoryLabel">Activity History</h4>
</div>
<div class="modal-body" id="modalHistoryBody">History</div>

</div>
</div>
</div>


@Html.Partial("~/Views/Shared/_PromotWorkflow.cshtml")

 

Step 7: Add the javascript methods to promote_workflow and show workflow_history:


<script type="text/javascript">
var history_link = "@Url.Action("History", "BusinessProcess", new { Area = "WorkflowManager", id = "0" })";
function promot_workflow(BusinessProcessID, nextstate, actionname, PlanID) {
$('#ParentBusinessProcessID').val(BusinessProcessID);
$('#stateID').val(nextstate);
$('#modalPromotionLabel').html(actionname);
$('#DOCUMENT_ID').val(DOCUMENT_ID);
$('#modalPromotion').modal();
}
function workflow_history(BusinessProcessID) {
$('#modalHistory').modal();
$('#modalHistoryBody').html("<div style='text-align:center;'> <img src='/content/images/loading.gif'/></div>");
$.post(history_link + BusinessProcessID, {},
function (data) {
$("#modalHistoryBody").html(data);
}
);
}

              </script>

 

Step 8: Get the current state of a document with C#: use this code


             [documentObject].BusinessProcess.CurrentState.BaseStateTemplate;

 

[PROCEED WITH CAUTION]
Step 9: Carefully dismantle prior implementations of status tracking on the document and change the document status implementations to workflow on all their occurrences.