Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions Server-Side Components/Business Rules/Approval Matrix/Matrix.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*Scenario :
Whenever a record (like an HR Case, Request Item, or Change) is created, the script:
Looks up the right approvers based on dynamic rules (department, amount, category, etc.)
Automatically creates approvals in the sysapproval_approver table.*/

/* Business Rule :

Table: sc_request or proc_po_request or custom table
When: After Insert
Condition: Only when approval is required */

(function executeRule(current, previous /*null when async*/) {

try {
var dept = current.u_department.name + '';
var amount = parseFloat(current.u_amount + '');
if (!dept || isNaN(amount)) {
gs.info('Approval Matrix: Missing department or amount');
return;
}

// Query approval matrix for matching rule
var matrix = new GlideRecord('u_approval_matrix');
matrix.addQuery('u_department.name', dept);
matrix.addQuery('u_min_amount', '<=', amount);
matrix.addQuery('u_max_amount', '>=', amount);
matrix.query();

if (!matrix.hasNext()) {
gs.info('Approval Matrix: No matching rule found for ' + dept + ', amount: ' + amount);
return;
}

while (matrix.next()) {
var approverUser = '';

// Option 1: Approver directly specified
if (!gs.nil(matrix.u_approver)) {
approverUser = matrix.u_approver;
}
// Option 2: Use role from requester’s hierarchy
else if (!gs.nil(matrix.u_role)) {
approverUser = getApproverByRole(current.requested_for, matrix.u_role + '');
}

if (approverUser) {
createApproval(current.sys_id, current.getTableName(), approverUser);
gs.info('Approval Matrix: Created approval for ' + approverUser);
}
}

} catch (ex) {
gs.error('Approval Matrix Error: ' + ex.message);
}

// --- Helper: Find approver based on user role ---
function getApproverByRole(userSysId, roleName) {
var usr = new GlideRecord('sys_user');
if (usr.get(userSysId)) {
if (roleName == 'Manager' && usr.manager) return usr.manager;
if (roleName == 'Director' && usr.u_director) return usr.u_director; // custom field
if (roleName == 'VP' && usr.u_vp) return usr.u_vp;
}
return '';
}

// --- Helper: Create approval record ---
function createApproval(targetSysId, targetTable, approverSysId) {
var appr = new GlideRecord('sysapproval_approver');
appr.initialize();
appr.sysapproval = targetSysId;
appr.table_name = targetTable;
appr.state = 'requested';
appr.approver = approverSysId;
appr.insert();
}

})(current, previous);
79 changes: 79 additions & 0 deletions Server-Side Components/Business Rules/Approval Matrix/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# ServiceNow Approval Matrix Generator
**A Dynamic, Data-Driven Approval Workflow Engine for ServiceNow**

---

## Overview

The **Approval Matrix Generator** is a configurable engine that automates approval generation in ServiceNow based on business rules —
without hard-coding approvers or creating dozens of Flow Designer flows.

By maintaining a simple **Approval Matrix table**, you can define which user or role should approve a request dynamically (e.g., based on department and amount).
This approach provides scalability, maintainability, and full visibility across all approval logic.

---

## Key Highlights

✅ 100% native ServiceNow solution (no plugins)
✅ Centralized approval logic in a single configuration table
✅ Works for ITSM, HRSD, Finance, or Procurement workflows
✅ Supports multi-level approvals (Manager → Director → CFO)
✅ Can run via **Business Rule**

---

## Use Case

An organization wants dynamic approval routing for procurement or HR requests based on:
- Department (IT, HR, Finance)
- Request amount (₹0–₹10,000, etc.)
- Approval role (Manager, Director, VP)

Instead of building multiple flows, the Approval Matrix defines all rules in a single table.
When a new request is submitted, the script automatically finds and assigns the correct approvers.

---

## Step 1 — Create Table `u_approval_matrix`

| Field | Type | Description |
|--------|------|-------------|
| **u_department** | Reference (sys_user_group) | Department owning the rule |
| **u_min_amount** | Decimal | Minimum amount for range |
| **u_max_amount** | Decimal | Maximum amount for range |
| **u_role** | Choice | Role type – Manager / Director / VP |
| **u_approver** | Reference (sys_user) | Direct approver (optional) |

This table drives all the logic.
Example data:

| Department | Min | Max | Role | Approver |
|-------------|-----|-----|------|-----------|
| IT | 0 | 5000 | Manager | *(blank)* |
| IT | 5000 | 10000 | Director | *(blank)* |
| Finance | 0 | 10000 | *(blank)* | John CFO |

---

## ⚙️ Step 2 — Business Rule Script

**Table:** `sc_request` (or your custom table)
**When:** After Insert
**Condition:** Approval required

## Example Input (Request Record)
| Field | Value |
| ------------- | ----------------- |
| Requested For | Ravi Gaurav |
| Department | IT |
| Amount | 8000 |
| Category | Hardware Purchase |

## Example Output
| Field | Value |
| -------------------- | ----------------------------------------- |
| Matched Rule | IT, 5000–10000, Role = Director |
| Approver Found | Ravi’s Director (from `u_director` field) |
| Approval State | Requested |
| sysapproval_approver | Created Automatically |
Loading