Parallel Approval Process

Applies To: SharePoint Online and On-Premises

Description

The Parallel Approval process allows multiple approvers to review and approve the request independently. The Manager and Director can approve the request in any order, and neither approval needs to wait for the other.

The overall flow is:

Pending Submission → Pending Approval → Manager + Director Approve Independently → Approved

The request is marked Approved only after both the Manager and Director have approved it.

  1. Submitter creates and submits the request.
    1. The Submitter enters all required information in the NITRO Form.
    1. The Submitter can save the request or submit it for approval.
    1. When submitted, the Status changes to Pending Approval.
    1. The request becomes available for both the Manager and Director to review.
  2. Manager and Director review the request independently.
    1. Either the Manager or Director can approve first.
    1. Approve: The respective approval status is updated to Approved.
    1. The overall Status remains Pending Approval until the other approver completes their approval.
    1. Deny: The overall Status changes to Denied, and the approval process is completed.
    1. Send Back: The overall Status changes to Sent Back, and the request is returned to the Submitter for corrections.
  3. When one approver approves first:
    1. The request remains in Pending Approval.
    1. The completed approver’s approval status is set to Approved.
    1. The other approver can still review and approve the request independently.
  4. When both approvers approve:
    1. The Manager Approval Status and Director Approval Status are both set to Approved.
    1. The overall Status changes to Approved.
    1. The Submitter can view the approved request.
  5. On Send Back:
    1. The Submitter reviews the comments provided by the Manager or Director.
    1. The Submitter makes the necessary changes to the request.
    1. The Submitter re-submits the request for approval.
    1. The Status changes back to Pending Approval, and both approval statuses are reset to Pending.
  6. On Deny:
    1. If either the Manager or Director denies the request, the overall Status changes to Denied.
    1. The Submitter can view the denied request and the comments provided by the approver.

Director Configuration

The Director is identified through a SharePoint Group named “Directors.”

Go to NITRO Studio → Site Permissions → Directors

If the Directors group does not exist, create and configure the SharePoint Group.

Note: The Approve, Deny, and Sent Back buttons are configured based on the logged-in user. These buttons are visible to the Manager when the logged-in user matches the user specified in the Manager column on the Request form. They are visible to the Director when the logged-in user is a member of the configured Directors SharePoint Group.

Refer to the table below to understand how the Status changes based on the Manager’s and Director’s decisions.

Manager ApprovalDirector ApprovalOverall Status
PendingPendingPending Approval
ApprovedPendingPending Approval
PendingApprovedPending Approval
ApprovedApprovedApproved
DeniedPending/ApprovedDenied
Pending/ApprovedDeniedDenied
Sent BackPending/ApprovedSent Back
Pending/ApprovedSent BackSent Back

Summary of steps:

  • List Schema
  • NITRO Forms Configuration
  • Approval Process Configuration
  • Notifications
  • Parallel Approval – Process Flow and Status Changes

List Schema

Refer Single Level Approval Process – Crow Canyon Software Support for list schema.

Use the same Requests list and columns configured for the Single-Level Approval Process, except for the values configured in the Status column and the two additional columns added to the Requests list.

ColumnPurpose Column Values
StatusTracks the overall status of the requestPending Submission Pending Approval Approved Denied Sent Back

In addition, add the following two columns to track the individual approval status of the Manager and Director:

ColumnColumn ValuesPurpose
Manager Approval StatusPending, ApprovedTracks the Manager’s approval
Director Approval StatusPending, ApprovedTracks the Director’s approval

NITRO Forms Configuration

To configure NITRO Forms

Navigate to List Settings → Crow Canyon NITRO Forms → Add Columns.

Form Configurations:

Action Button Permissions

ButtonDefaultShow ConditionWho Can See It
Submit for ApprovalHide for allStatus = Pending Submission or Sent BackSubmitter
ApproveHide for allStatus = Pending Approval AND Manager Approval Status = PendingManager
 DenyHide for allManager Approval Status = PendingManager
Sent BackHide for allManager Approval Status = PendingManager
ApproveHide for allStatus = Pending Approval AND Director Approval Status = PendingDirector
DenyHide for allDirector Approval Status = PendingDirector
Sent BackHide for allDirector Approval Status = PendingDirector

Refer to the Single-Level Approval NITRO Form Configuration section in Single Level Approval Process – Crow Canyon Software Support for configuring columns, buttons, permissions, and validations.

Approval Process Configuration

The approval process is configured using submit action buttons in NITRO forms. We can drag and drop the submit action buttons on the form.

Below, we have described the action buttons and the script used to update the status of the request.

Action Button: Save

  • This is the default save button on the form. This will save the Item in the Requests list.

Role: Submitter

Action Button: Submit for Approval

  • This action button will set the status to “Pending Approval”
  • Set the Manager Approval Status to Pending
  • Set the Director Approval Status to Pending
    • Updates the Process Log
    • Captures the “Submitted By” and “Submitted On”

Note: When the request is in Sent Back status, the Submit button is available to allow the Submitter to resubmit the request. Upon resubmission, the Status changes to Pending Manager Approval.

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
formContext.setColumnControlValueByName("Status","Pending Approval");
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("Status","Pending Submission");
    }
};
listColumnValueobj["ManagerApprovalStatus"] = "Pending";
listColumnValueobj["DirectorApprovalStatus"] = "Pending";
listColumnValueobj["ProcessLog"] = "Request is submitted by " + userName + " and waiting for approval";

listColumnValueobj["SubmittedOn"] = new Date();
listColumnValueobj["SubmittedBy"] = userName;
functionCallback(false, listColumnValueobj, "", advSettings);

Script Explanation

ScriptExplanation
userName = _spPageContextInfo.userDisplayNameGets the logged-in user’s display name.
Status = “Pending Approval”Changes the overall request status to Pending Approval.
ManagerApprovalStatus = “Pending”Initializes Manager approval.
DirectorApprovalStatus = “Pending”Initializes Director approval.
SubmittedOn = new Date()Records the submission date and time.
SubmittedBy = userNameRecords the person who submitted the request.
ProcessLogRecords that the request was submitted and is waiting for approval.
FailIf the operation fails, the Status is returned to Pending Submission.
functionCallback()Saves the values to the item.

Role: Manager

Action Button: Approve

  • This action button will be shown to the Manager when status is “Pending Approval” and Manager Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like Approved By and Approved On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varDirectorApproval = formContext.fetchColumnValueUI("DirectorApprovalStatus");
var varProcessLog = "";
formContext.setColumnControlValueByName("ManagerApprovalStatus","Approved");

if(varDirectorApproval == "Approved"){
formContext.setColumnControlValueByName("Status","Approved");
varProcessLog = "Request is approved by the Manager: " + userName;
}
else{
varProcessLog = "Request is approved by the Manager: " + userName + " and waiting for director approval";

}
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("ManagerApprovalStatus","Pending");
		formContext.setColumnControlValueByName("Status","Pending Approval");

    }
};
 listColumnValueobj["ApprovedOn"] = new Date();
listColumnValueobj["ApprovedBy"] = userName;
listColumnValueobj["ProcessLog"] = varProcessLog;
functionCallback(false, listColumnValueobj, "", advSettings);

Script Explanation

ScriptExplanation
userNameGets the logged-in Manager’s name.
fetchColumnValueUI(“DirectorApprovalStatus”)Gets the current Director approval status.
currentItem.get_item(“Status”)Stores the current overall Status so it can be restored if the operation fails.
ManagerApprovalStatus = “Approved”Marks the Manager approval as completed.
if (varDirectorApproval == “Approved”)Checks whether the Director has already approved.
Status = “Approved”If both approvals are now complete, changes the overall Status to Approved.
elseIf the Director has not approved yet, the overall Status remains Pending Approval.
ApprovedOn = new Date()Records when the approval occurred.
ApprovedBy = userNameRecords who performed the approval.
ProcessLogRecords the Manager approval activity.
FailRestores the previous Manager Approval Status and overall Status if saving fails.

Action Button: Deny

  • This action button will be shown to the Manager when status is “Pending Approval” and Manager Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like Denied By and Denied On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varCurrentStatus = currentItem.get_item("Status");
formContext.setColumnControlValueByName("Status","Denied");
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("Status",varCurrentStatus);
    }
};
listColumnValueobj["DirectorApprovalStatus"] = "";
listColumnValueobj["ManagerApprovalStatus"] = "";
listColumnValueobj["ProcessLog"] = "Request is denied by Manager " + userName;
listColumnValueobj["DeniedOn"] = new Date();
listColumnValueobj["DeniedBy"] = userName;
functionCallback(false, listColumnValueobj, "", advSettings);

Action Button: Sent Back

  • This action button will be shown to the Manager when status is “Pending Approval” and Manager Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like SentBack By and SentBack On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varCurrentStatus = currentItem.get_item("Status");
formContext.setColumnControlValueByName("Status","Sent Back");
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("Status",varCurrentStatus);
    }
};
listColumnValueobj["DirectorApprovalStatus"] = "";
listColumnValueobj["ManagerApprovalStatus"] = "";
listColumnValueobj["ProcessLog"] = "Request is sent back by Manager " + userName;
listColumnValueobj["SentBackOn"] = new Date();
listColumnValueobj["SentBackBy"] = userName;
functionCallback(false, listColumnValueobj, "", advSettings);

Role: Director

Action Button: Approve

  • This action button will be shown to the Director when status is “Pending Approval” and Director Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like Approved By and Approved On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varManagerApproval = formContext.fetchColumnValueUI("ManagerApprovalStatus");
var varProcessLog = "";
formContext.setColumnControlValueByName("DirectorApprovalStatus","Approved");

if(varManagerApproval == "Approved"){
formContext.setColumnControlValueByName("Status","Approved");
varProcessLog = "Request is approved by the Director: " + userName;
}
else{
varProcessLog = "Request is approved by the Director: " + userName + " and waiting for manager approval";

}
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("DirectorApprovalStatus","Pending");
		formContext.setColumnControlValueByName("Status","Pending Approval");
    }
};
listColumnValueobj["ApprovedOn"] = new Date();
listColumnValueobj["ApprovedBy"] = userName;
listColumnValueobj["ProcessLog"] = varProcessLog;
functionCallback(false, listColumnValueobj, "", advSettings);

Action Button: Deny

  • This action button will be shown to the Director when status is “Pending Approval” and Director Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like Denied By and Denied On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varCurrentStatus = currentItem.get_item("Status");
formContext.setColumnControlValueByName("Status","Denied");
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("Status",varCurrentStatus);
    }
};
listColumnValueobj["DirectorApprovalStatus"] = "";
listColumnValueobj["ManagerApprovalStatus"] = "";
listColumnValueobj["ProcessLog"] = "Request is denied by Director " + userName;
listColumnValueobj["DeniedOn"] = new Date();
listColumnValueobj["DeniedBy"] = userName;
functionCallback(false, listColumnValueobj, "", advSettings);

Action Button: Sent Back

  • This action button will be shown to the Director when status is “Pending Approval” and Director Approval Status is “Pending”.
  • Updates the Process Log
  • Captures the approver details like SentBack By and SentBack On

Script used:

var listColumnValueobj = {};
var userName = _spPageContextInfo.userDisplayName;
var varCurrentStatus = currentItem.get_item("Status");
formContext.setColumnControlValueByName("Status","Sent Back");
var advSettings = {Validate : true,Fail: function(){
        formContext.setColumnControlValueByName("Status",varCurrentStatus);
    }
};
listColumnValueobj["DirectorApprovalStatus"] = "";
listColumnValueobj["ManagerApprovalStatus"] = "";
listColumnValueobj["ProcessLog"] = "Request is sent back by Director " + userName;
listColumnValueobj["SentBackOn"] = new Date();
listColumnValueobj["SentBackBy"] = userName;
functionCallback(false, listColumnValueobj, "", advSettings);

Notifications

Refer Single-Level Approval Notifications section in Single Level Approval Process – Crow Canyon Software Support to configure this.

Parallel Approval – Process Flow and Status Changes

  1. Create Request
    Submitter creates and saves or submit the request. Status: Pending Submission

2. Submit Request
Submitter submits the request for approval. Status: Pending Approval. Both Manager Approval Status and Director Approval Status are set to Pending.

3. Manager and Director Approve Independently
The Manager and Director can approve the request independently. Each approval changes the corresponding approval status to Approved, while the overall Status remains Pending Approval until both approvals are completed.

Director Approve the Request first:

Then Manager Approves the Request

4. Both Approvals Completed
Once both the Manager and Director have approved the request, the overall Status changes to Approved.

Note: In the parallel approval process, either the Manager or Director can approve the request first. The other approver can then approve the request independently. The request is marked Approved only after both the Manager and Director have approved it.

Alternate Approval Outcomes

Manager/Director Denies → Overall Status: Denied → Approval Process Ends

Manager/Director Sends Back → Overall Status: Sent Back → Submitter Updates Request → Re-submits → Status: Pending Approval

When the request is Sent Back, the Submitter can make the necessary changes and re-submit the request for approval.