From aba90d6c7041f7841a26e02c4e65b9c802bab79c Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 17:36:59 +0530 Subject: [PATCH 1/7] Create Catalog.js Catalog Builder API - A Scripted REST API to auto-create ServiceNow Catalog Items programmatically. --- .../Catalog.js | 120 ++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js diff --git a/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js b/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js new file mode 100644 index 0000000000..d52fafb054 --- /dev/null +++ b/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js @@ -0,0 +1,120 @@ +// Scenario : As a ServiceNow Admin or Developer managing dozens of similar request forms (like “Request Laptop”, “Request Mobile”, “Request Access”, etc.). +// Manually creating each catalog item is repetitive. + +// This code will Automate Catalog Item Creation with a Single REST Call +//Script: POST /api/x_demo/catalog_creator/create + +(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) { + + var body = request.body.data; + var result = {}; + + try { + // 1. Create Catalog Item + var catItem = new GlideRecord('sc_cat_item'); + catItem.initialize(); + catItem.name = body.name; + catItem.short_description = body.short_description || ''; + catItem.description = body.description || ''; + catItem.category = getCategorySysId(body.category); + catItem.owning_group = getOwner(body.owner); + catItem.active = true; + var catSysId = catItem.insert(); + + result.catalog_sys_id = catSysId; + + // 2. Create Variables + if (body.variables && body.variables.length > 0) { + for (var i = 0; i < body.variables.length; i++) { + var v = body.variables[i]; + + var variable = new GlideRecord('item_option_new'); + variable.initialize(); + variable.cat_item = catSysId; + variable.name = v.name.toLowerCase().replace(/ /g, '_'); + variable.question_text = v.name; + variable.type = getType(v.type); + variable.order = (i + 1) * 100; + var varSysId = variable.insert(); + + // Add choices for select box variables + if (v.choices && v.choices.length > 0) { + var choices = v.choices.split(','); + for (var j = 0; j < choices.length; j++) { + var choice = new GlideRecord('question_choice'); + choice.initialize(); + choice.question = varSysId; + choice.value = choices[j].trim(); + choice.label = choices[j].trim(); + choice.insert(); + } + } + } + } + + result.message = "Catalog item created successfully!"; + response.setStatus(201); + + } catch (e) { + gs.error("Error creating catalog item: " + e); + result.message = e.toString(); + response.setStatus(500); + } + + response.setBody(result); + + + function getCategorySysId(categoryName) { + var cat = new GlideRecord('sc_category'); + cat.addQuery('title', categoryName); + cat.query(); + if (cat.next()) return cat.sys_id; + return null; + } + + function getOwner(ownerName) { + var usr = new GlideRecord('sys_user'); + usr.addQuery('user_name', ownerName); + usr.query(); + if (usr.next()) return usr.sys_id; + return gs.getUserID(); + } + + function getType(typeName) { + var map = { + "single_line_text": 1, + "multi_line_text": 2, + "select_box": 3, + "reference": 8, + "checkbox": 5 + }; + return map[typeName] || 1; + } + +})(request, response); + +//Example JSON +//{ + "name": "Request New Laptop", + "category": "Hardware", + "short_description": "Laptop provisioning form", + "description": "Allows employees to request a new laptop.", + "owner": "admin", + "variables": [ + { + "name": "Laptop Model", + "type": "select_box", + "choices": "Dell,HP,Lenovo" + }, + { + "name": "RAM Size", + "type": "select_box", + "choices": "8GB,16GB,32GB" + }, + { + "name": "Business Justification", + "type": "multi_line_text" + } + ] +} + From 45a3fcdd6a11143b6d3e83b6eadd3185a28329b9 Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 17:39:29 +0530 Subject: [PATCH 2/7] Create README.md This readme file has info about how to Automate Catalog Item Creation with a Single REST Call. --- .../Create Catalog Item Dynamically/README.md | 99 +++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md diff --git a/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md b/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md new file mode 100644 index 0000000000..600ccae368 --- /dev/null +++ b/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md @@ -0,0 +1,99 @@ +# ServiceNow Catalog Builder API +**Automate Catalog Item Creation with a Single REST Call** + +--- + +## Overview + +The **ServiceNow Catalog Builder API** is a custom **Scripted REST API** that dynamically creates Service Catalog Items in your instance — including variables and choices — from a simple JSON payload. + +This API eliminates the repetitive manual work of configuring Catalog Items one by one, and makes it possible to **automate catalog creation programmatically** or **integrate it with CI/CD pipelines, GitHub workflows, or external systems**. + +--- + +## Key Features + +Automatically create **Catalog Items** in `sc_cat_item` +Dynamically generate **Variables** and **Choices** +Supports **category mapping** and **item ownership** +Extensible design for **flows, icons, and attachments** +Developer-friendly — fully JSON-driven + +--- + +## Use Case + +This API is perfect for: +- **Admin Automation:** Auto-build standard catalog forms during environment setup. +- **RPA / CI Pipelines:** Integrate with DevOps or GitHub Actions to deploy catalog definitions. +- **Dynamic Service Portals:** Allow external apps or portals to create items on demand. + +Example: +A company wants to auto-create 10 new service catalog items from a GitHub configuration file. +Using this API, they simply call one REST endpoint for each definition — no manual clicks needed. + +--- + +## ⚙️ Scripted REST API Details + +| Property | Value | +|-----------|--------| +| **Name** | Catalog Builder API | +| **API ID** | `x_demo.catalog_creator` | +| **Resource Path** | `/create` | +| **Method** | POST | +| **Authentication** | Basic Auth / OAuth | +| **Tables Used** | `sc_cat_item`, `item_option_new`, `question_choice` | + +--- + +## Logic Flow + +1. **Receive JSON input** with item name, category, and variables. +2. **Create a new record** in `sc_cat_item`. +3. **Loop through variables** and create them in `item_option_new`. +4. If the variable type is `select_box`, create **choices** automatically. +5. Return a JSON response with the new item’s `sys_id` and success message. + +--- + +## 🧾 Example Input (POST Body) + +```json +{ + "name": "Request New Laptop", + "category": "Hardware", + "short_description": "Laptop provisioning request form", + "description": "Allows employees to request a new laptop with model and RAM options.", + "owner": "admin", + "variables": [ + { + "name": "Laptop Model", + "type": "select_box", + "choices": "Dell,HP,Lenovo" + }, + { + "name": "RAM Size", + "type": "select_box", + "choices": "8GB,16GB,32GB" + }, + { + "name": "Business Justification", + "type": "multi_line_text" + } + ] +} + + +Example Output: +{ + "catalog_sys_id": "b2f6329cdb6d0010355b5fb4ca9619e2", + "message": "Catalog item created successfully!" +} +After the API call: +A new Catalog Item appears under Maintain Items. +The item contains: +Short Description: Laptop provisioning form +Variables: Laptop Model, RAM Size, Business Justification +Choices: Auto-populated for select boxes +The item is active and ready to use in the catalog. From c3c70a363353c19f8047f67f27941f0c67db52ac Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 17:43:10 +0530 Subject: [PATCH 3/7] Update README.md Automate Catalog Item Creation with a Single REST Call --- .../Create Catalog Item Dynamically/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md b/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md index 600ccae368..4333f8ceb9 100644 --- a/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md +++ b/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md @@ -34,7 +34,7 @@ Using this API, they simply call one REST endpoint for each definition — no ma --- -## ⚙️ Scripted REST API Details +## Scripted REST API Details | Property | Value | |-----------|--------| @@ -57,7 +57,7 @@ Using this API, they simply call one REST endpoint for each definition — no ma --- -## 🧾 Example Input (POST Body) +## Example Input (POST Body) ```json { @@ -85,7 +85,7 @@ Using this API, they simply call one REST endpoint for each definition — no ma } -Example Output: +## Example Output: { "catalog_sys_id": "b2f6329cdb6d0010355b5fb4ca9619e2", "message": "Catalog item created successfully!" From 0c43396a6292cfee8cecee51a34827cc7f333bc6 Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 17:45:55 +0530 Subject: [PATCH 4/7] Delete Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md --- .../Create Catalog Item Dynamically/README.md | 99 ------------------- 1 file changed, 99 deletions(-) delete mode 100644 Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md diff --git a/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md b/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md deleted file mode 100644 index 4333f8ceb9..0000000000 --- a/Integration/Scripted REST Api/Create Catalog Item Dynamically/README.md +++ /dev/null @@ -1,99 +0,0 @@ -# ServiceNow Catalog Builder API -**Automate Catalog Item Creation with a Single REST Call** - ---- - -## Overview - -The **ServiceNow Catalog Builder API** is a custom **Scripted REST API** that dynamically creates Service Catalog Items in your instance — including variables and choices — from a simple JSON payload. - -This API eliminates the repetitive manual work of configuring Catalog Items one by one, and makes it possible to **automate catalog creation programmatically** or **integrate it with CI/CD pipelines, GitHub workflows, or external systems**. - ---- - -## Key Features - -Automatically create **Catalog Items** in `sc_cat_item` -Dynamically generate **Variables** and **Choices** -Supports **category mapping** and **item ownership** -Extensible design for **flows, icons, and attachments** -Developer-friendly — fully JSON-driven - ---- - -## Use Case - -This API is perfect for: -- **Admin Automation:** Auto-build standard catalog forms during environment setup. -- **RPA / CI Pipelines:** Integrate with DevOps or GitHub Actions to deploy catalog definitions. -- **Dynamic Service Portals:** Allow external apps or portals to create items on demand. - -Example: -A company wants to auto-create 10 new service catalog items from a GitHub configuration file. -Using this API, they simply call one REST endpoint for each definition — no manual clicks needed. - ---- - -## Scripted REST API Details - -| Property | Value | -|-----------|--------| -| **Name** | Catalog Builder API | -| **API ID** | `x_demo.catalog_creator` | -| **Resource Path** | `/create` | -| **Method** | POST | -| **Authentication** | Basic Auth / OAuth | -| **Tables Used** | `sc_cat_item`, `item_option_new`, `question_choice` | - ---- - -## Logic Flow - -1. **Receive JSON input** with item name, category, and variables. -2. **Create a new record** in `sc_cat_item`. -3. **Loop through variables** and create them in `item_option_new`. -4. If the variable type is `select_box`, create **choices** automatically. -5. Return a JSON response with the new item’s `sys_id` and success message. - ---- - -## Example Input (POST Body) - -```json -{ - "name": "Request New Laptop", - "category": "Hardware", - "short_description": "Laptop provisioning request form", - "description": "Allows employees to request a new laptop with model and RAM options.", - "owner": "admin", - "variables": [ - { - "name": "Laptop Model", - "type": "select_box", - "choices": "Dell,HP,Lenovo" - }, - { - "name": "RAM Size", - "type": "select_box", - "choices": "8GB,16GB,32GB" - }, - { - "name": "Business Justification", - "type": "multi_line_text" - } - ] -} - - -## Example Output: -{ - "catalog_sys_id": "b2f6329cdb6d0010355b5fb4ca9619e2", - "message": "Catalog item created successfully!" -} -After the API call: -A new Catalog Item appears under Maintain Items. -The item contains: -Short Description: Laptop provisioning form -Variables: Laptop Model, RAM Size, Business Justification -Choices: Auto-populated for select boxes -The item is active and ready to use in the catalog. From 0bc1af4b02aba1d1b5f454b3c75aee5a030acb50 Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 17:46:07 +0530 Subject: [PATCH 5/7] Delete Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js --- .../Catalog.js | 120 ------------------ 1 file changed, 120 deletions(-) delete mode 100644 Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js diff --git a/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js b/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js deleted file mode 100644 index d52fafb054..0000000000 --- a/Integration/Scripted REST Api/Create Catalog Item Dynamically/Catalog.js +++ /dev/null @@ -1,120 +0,0 @@ -// Scenario : As a ServiceNow Admin or Developer managing dozens of similar request forms (like “Request Laptop”, “Request Mobile”, “Request Access”, etc.). -// Manually creating each catalog item is repetitive. - -// This code will Automate Catalog Item Creation with a Single REST Call -//Script: POST /api/x_demo/catalog_creator/create - -(function process(/*RESTAPIRequest*/ request, /*RESTAPIResponse*/ response) { - - var body = request.body.data; - var result = {}; - - try { - // 1. Create Catalog Item - var catItem = new GlideRecord('sc_cat_item'); - catItem.initialize(); - catItem.name = body.name; - catItem.short_description = body.short_description || ''; - catItem.description = body.description || ''; - catItem.category = getCategorySysId(body.category); - catItem.owning_group = getOwner(body.owner); - catItem.active = true; - var catSysId = catItem.insert(); - - result.catalog_sys_id = catSysId; - - // 2. Create Variables - if (body.variables && body.variables.length > 0) { - for (var i = 0; i < body.variables.length; i++) { - var v = body.variables[i]; - - var variable = new GlideRecord('item_option_new'); - variable.initialize(); - variable.cat_item = catSysId; - variable.name = v.name.toLowerCase().replace(/ /g, '_'); - variable.question_text = v.name; - variable.type = getType(v.type); - variable.order = (i + 1) * 100; - var varSysId = variable.insert(); - - // Add choices for select box variables - if (v.choices && v.choices.length > 0) { - var choices = v.choices.split(','); - for (var j = 0; j < choices.length; j++) { - var choice = new GlideRecord('question_choice'); - choice.initialize(); - choice.question = varSysId; - choice.value = choices[j].trim(); - choice.label = choices[j].trim(); - choice.insert(); - } - } - } - } - - result.message = "Catalog item created successfully!"; - response.setStatus(201); - - } catch (e) { - gs.error("Error creating catalog item: " + e); - result.message = e.toString(); - response.setStatus(500); - } - - response.setBody(result); - - - function getCategorySysId(categoryName) { - var cat = new GlideRecord('sc_category'); - cat.addQuery('title', categoryName); - cat.query(); - if (cat.next()) return cat.sys_id; - return null; - } - - function getOwner(ownerName) { - var usr = new GlideRecord('sys_user'); - usr.addQuery('user_name', ownerName); - usr.query(); - if (usr.next()) return usr.sys_id; - return gs.getUserID(); - } - - function getType(typeName) { - var map = { - "single_line_text": 1, - "multi_line_text": 2, - "select_box": 3, - "reference": 8, - "checkbox": 5 - }; - return map[typeName] || 1; - } - -})(request, response); - -//Example JSON -//{ - "name": "Request New Laptop", - "category": "Hardware", - "short_description": "Laptop provisioning form", - "description": "Allows employees to request a new laptop.", - "owner": "admin", - "variables": [ - { - "name": "Laptop Model", - "type": "select_box", - "choices": "Dell,HP,Lenovo" - }, - { - "name": "RAM Size", - "type": "select_box", - "choices": "8GB,16GB,32GB" - }, - { - "name": "Business Justification", - "type": "multi_line_text" - } - ] -} - From 9f876c50124b78e4d8b438e78ac9d17119542b1e Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 20:43:28 +0530 Subject: [PATCH 6/7] Create Matrix.js Instead of hardcoding approvals in Flow Designer or scripting them per catalog item, you can maintain one Approval Matrix table. --- .../Business Rules/Approval Matrix/Matrix.js | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 Server-Side Components/Business Rules/Approval Matrix/Matrix.js 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); From d719e9c22ecd9ea1b270a870ce3a2297c1eed8d2 Mon Sep 17 00:00:00 2001 From: Ravi Gaurav Date: Tue, 14 Oct 2025 20:45:57 +0530 Subject: [PATCH 7/7] Create README.md The ServiceNow Approval Matrix Generator is a configurable, data-driven engine that automatically assigns approvers based on business rules such as department, amount, or role. --- .../Business Rules/Approval Matrix/README.md | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 Server-Side Components/Business Rules/Approval Matrix/README.md 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 |