diff --git a/Server-Side Components/Business Rules/Approval Matrix/Matrix.js b/Server-Side Components/Business Rules/Approval Matrix/Matrix.js new file mode 100644 index 0000000000..ae507a35e0 --- /dev/null +++ b/Server-Side Components/Business Rules/Approval Matrix/Matrix.js @@ -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); diff --git a/Server-Side Components/Business Rules/Approval Matrix/README.md b/Server-Side Components/Business Rules/Approval Matrix/README.md new file mode 100644 index 0000000000..3295e8a9ef --- /dev/null +++ b/Server-Side Components/Business Rules/Approval Matrix/README.md @@ -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 |