Skip to content

Commit c3f00eb

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into main
2 parents f2ce7d2 + 9ce4d27 commit c3f00eb

File tree

7 files changed

+212
-0
lines changed

7 files changed

+212
-0
lines changed
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
function executeRule(current, previous /*null when async*/){
2+
if(current.close_code){
3+
var taskGR = new GlideRecord('change_task');
4+
taskGR.addQuery('change_request', current.sys_id);
5+
taskGR.addQuery('state', '!=', '3') // Adjust as needed
6+
taskGR.query();
7+
8+
if (taskGR.hasNext()){
9+
gs.addErrorMessage('You cannot close this change request until all change tasks are closed.');
10+
current.setAbortAction(true); // Prevent saving the form
11+
}
12+
}
13+
14+
})(current, previous);
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
Prevent Closure if the change tasks are open
2+
3+
1. Create a Before Business Rule.
4+
2. Applicable to Change Request Table.
5+
3. Use Before - Update Business Rule.
6+
4. Add filter conditions if required.
7+
5. Apply the Business Rule script.
8+
6. If the change request have the active change tasks are still open then we can't proceed with the submission.
9+
7. If required we can add few more query conditions.
10+
8.
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
# Business Rule: Validate Update Set Scope
3+
4+
5+
## Challenge
6+
7+
When working with update sets, mismatched scopes can lead to issues during the preview process in the target instance. This often results in errors that require manual intervention to resolve. Such errors can be time-consuming, especially for minor mismatches that could have been identified and prevented earlier. This challenge highlights the need for a mechanism to validate update set scopes before completion, saving time and effort during deployment.
8+
9+
10+
## Overview
11+
This business rule ensures that all customer updates within an update set match the application scope of the update set. If any updates have mismatched scopes, the business rule restricts the completion of the update set and displays a message listing the files with mismatched scopes.
12+
13+
## Features
14+
- Validates the scope of all updates in an update set.
15+
- Prevents the completion of an update set if scope mismatches are detected.
16+
- Displays a detailed message listing the files with mismatched scopes.
17+
18+
## Use Case
19+
This business rule is useful for ensuring that updates in an update set adhere to the correct application scope, preventing potential issues caused by scope mismatches.
20+
21+
## Implementation
22+
23+
### 1. Create the Business Rule
24+
1. Navigate to **System Definition > Business Rules** in your ServiceNow instance.
25+
2. Click **New** to create a new business rule.
26+
3. Configure the business rule as follows:
27+
- **Name**: Validate Update Set Scope
28+
- **Table**: `sys_update_set`
29+
- **When**: Before
30+
- **Insert**: False
31+
- **Update**: True
32+
- **Delete**: False
33+
34+
### 2. Add the Script
35+
Use the following script in the **Script** field:
36+
37+
```javascript
38+
(function executeRule(current, previous /*null when async*/) {
39+
40+
// Add attached code here
41+
42+
})(current, previous);
43+
44+
```
45+
46+
### 3. Test the Business Rule
47+
1. Create an update set and add updates with different scopes.
48+
2. Attempt to complete the update set.
49+
3. Verify that the business rule prevents completion and displays the appropriate error message.
50+
51+
52+
## Screenshots
53+
![Output Result](error.png)
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
(function executeRule(current, previous /*null when async*/) {
2+
3+
// Add your code here
4+
5+
var updateSetSysId = current.sys_id; // Get the sys_id of the current update set
6+
var updateSetScope = current.application; // Get the scope of the current update set
7+
var gr = new GlideRecord('sys_update_xml');
8+
gr.addQuery('update_set', updateSetSysId); // Query for records in the current update set
9+
gr.query();
10+
11+
var misMatchedUpdates = [];
12+
while (gr.next()) {
13+
if (gr.application != updateSetScope) { // Check if the scope matches the update set scope
14+
misMatchedUpdates.push( gr.target_name.toString() + ' (' + gr.type.toString() + ')'); // Collect the file names with mismatched scope
15+
}
16+
}
17+
18+
if (misMatchedUpdates.length > 0) {
19+
gs.addErrorMessage('The following files have a different scope than the update set scope: \n' + misMatchedUpdates.join(', '));
20+
current.setAbortAction(true); // Prevent the update set from being completed
21+
}
22+
23+
24+
25+
})(current, previous);
153 KB
Loading
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# AuditFieldChangeNotifier
2+
### Description
3+
A ServiceNow Script Include that audits changes to specific fields and sends real-time notifications to Slack or Microsoft Teams using a webhook.
4+
It helps teams monitor important updates like priority or assignment changes without needing to check the platform.
5+
---
6+
### 🔧 Features
7+
- Monitors field-level changes on any table
8+
- Sends rich notifications to Slack/Teams
9+
- Easy to configure via system properties
10+
- Can be reused across multiple tables via Business Rules
11+
---
12+
### 🧩 How to Use
13+
1. **Create a System Property**
14+
- Name: `x_custom.audit_notifier.webhook_url`
15+
- Value: Your Slack or Teams webhook URL
16+
2. **Create a Script Include**
17+
- Name: `AuditFieldChangeNotifier`
18+
- Paste the provided Script Include code
19+
3. **Create a Business Rule**
20+
- Table: e.g. `incident`
21+
- When: `after update`
22+
- Add this script:
23+
```js
24+
(function executeRule(current, previous) {
25+
var notifier = new AuditFieldChangeNotifier();
26+
notifier.notifyOnFieldChange(current, previous, ['priority', 'state', 'assigned_to']);
27+
})(current, previous);
28+
```
29+
4. **Test It**
30+
- Update one of the watched fields.
31+
- A message should appear in your Slack/Teams channel like:
32+
```
33+
🛠️ ServiceNow — Field Update Notification
34+
Record: Incident INC0010001
35+
Description: Unable to access VPN
36+
• priority changed from 4 - Low → 2 - High
37+
• assigned_to changed from John → Alex
38+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Script Include: AuditFieldChangeNotifier
3+
* Description: Sends Slack/Teams notifications when specific fields change on configured tables.
4+
* Usable in: Business Rule (after update)
5+
*/
6+
var AuditFieldChangeNotifier = Class.create();
7+
AuditFieldChangeNotifier.prototype = {
8+
initialize: function () {
9+
// Slack or Teams webhook URL (store in sys_properties for security)
10+
this.webhookUrl = gs.getProperty('x_custom.audit_notifier.webhook_url', '');
11+
// Default app name
12+
this.appName = gs.getProperty('x_custom.audit_notifier.app_name', 'ServiceNow');
13+
},
14+
/**
15+
* Send notification if the specified fields have changed
16+
* @param {GlideRecord} current - Current record
17+
* @param {GlideRecord} previous - Previous record
18+
* @param {Array} fieldsToWatch - Array of field names to monitor
19+
*/
20+
notifyOnFieldChange: function (current, previous, fieldsToWatch) {
21+
try {
22+
if (!this.webhookUrl) {
23+
gs.warn('[AuditFieldChangeNotifier] Webhook URL not configured.');
24+
return;
25+
}
26+
var changes = [];
27+
fieldsToWatch.forEach(function (field) {
28+
if (current[field] + '' !== previous[field] + '') {
29+
changes.push({
30+
field: field,
31+
oldValue: previous[field] + '',
32+
newValue: current[field] + ''
33+
});
34+
}
35+
});
36+
if (changes.length === 0)
37+
return; // No relevant field changed
38+
var payload = this._buildPayload(current, changes);
39+
this._sendWebhook(payload);
40+
} catch (e) {
41+
gs.error('[AuditFieldChangeNotifier] Error: ' + e.message);
42+
}
43+
},
44+
/**
45+
* Build payload for Slack/Teams message
46+
*/
47+
_buildPayload: function (current, changes) {
48+
var shortDesc = current.short_description ? current.short_description + '' : '(No short description)';
49+
var tableName = current.getTableName();
50+
var recordUrl = gs.getProperty('glide.servlet.uri') + tableName + '.do?sys_id=' + current.sys_id;
51+
var changeLines = changes.map(function (c) {
52+
return `• *${c.field}* changed from _${c.oldValue}_ → *${c.newValue}*`;
53+
}).join('\n');
54+
return JSON.stringify({
55+
text: `🛠️ *${this.appName}* — Field Update Notification\n\n*Record:* <${recordUrl}|${tableName}> \n*Description:* ${shortDesc}\n\n${changeLines}\n\n_Updated by ${gs.getUserDisplayName()}_`
56+
});
57+
},
58+
/**
59+
* Send payload to webhook
60+
*/
61+
_sendWebhook: function (payload) {
62+
var r = new sn_ws.RESTMessageV2();
63+
r.setEndpoint(this.webhookUrl);
64+
r.setHttpMethod('POST');
65+
r.setRequestHeader('Content-Type', 'application/json');
66+
r.setRequestBody(payload);
67+
var response = r.execute();
68+
if (response.getStatusCode() >= 400)
69+
gs.error('[AuditFieldChangeNotifier] Webhook error: ' + response.getBody());
70+
},
71+
type: 'AuditFieldChangeNotifier'
72+
};

0 commit comments

Comments
 (0)