Skip to content

Commit b3a3ed6

Browse files
authored
Merge branch 'ServiceNowDevProgram:main' into feature/NewGSMessages
2 parents e247993 + 81d7759 commit b3a3ed6

File tree

12 files changed

+308
-0
lines changed

12 files changed

+308
-0
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
(function executeAction() {
2+
var grCase = new GlideRecord('sn_customerservice_case');
3+
grCase.addQuery('parent', current.sys_id);
4+
grCase.query();
5+
6+
var counter = 0;
7+
while (grCase.next()) {
8+
if (grCase.state != 3) { // 3 = Closed
9+
grCase.resolution_code = '16';
10+
grCase.close_notes = 'This case was auto closed from the parent case.';
11+
grCase.state = 3;
12+
grCase.update();
13+
counter++;
14+
}
15+
}
16+
17+
// Show info message only if any cases were closed
18+
if (counter > 0) {
19+
gs.addInfoMessage(counter + ' child case(s) have been closed.');
20+
}
21+
22+
action.setRedirectURL(current);
23+
})();
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Name: Close all Child Case
2+
Table:sn_customerservice_case
3+
Condition: (gs.hasRole('sn_customerservice_agent') || gs.hasRole('admin') ) && (new GlideRecord('sn_customerservice_case').addQuery('parent', current.sys_id).query().hasNext())
4+
5+
Use Case:
6+
Provide UI action button to close all the associated child cases from the parent Case.
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
This solution provides a significant User Experience (UX) enhancement for fields that store complex data in JSON format (e.g., integration payloads, configuration properties, or setup data).
2+
3+
Instead of forcing users (developers, administrators) to read or edit raw, unformatted JSON in a plain text area, this macro adds a "JSON Viewer" button next to the field
4+
5+
Name json_formatter_macro
6+
Active true
7+
Type XML
8+
9+
Navigate to **System UI > UI** Macros and create a new record named json_formatter_macro , Use XML Attached File as Script
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="jelly:html" xmlns:g2="glide.ui">
3+
4+
<g:evaluate var="jvar_field_name" expression="RP.getWindowProperties().get('fieldName')" />
5+
6+
<button type="button"
7+
onclick="openJsonViewer('${jvar_field_name}');"
8+
title="View and Format JSON"
9+
class="btn btn-default btn-sm">
10+
<span class="icon-code"></span> JSON Viewer
11+
</button>
12+
13+
<script>
14+
function openJsonViewer(fieldName) {
15+
var jsonValue = g_form.getValue(fieldName);
16+
var gm = new GlideModal('json_viewer_ui_page', false); // Replace 'json_viewer_ui_page' with your actual UI Page or Widget ID
17+
gm.setTitle('JSON Data Viewer & Formatter for Field: ' + fieldName);
18+
gm.setPreference('json_data', jsonValue);
19+
gm.setSize(900);
20+
gm.render();
21+
}
22+
</script>
23+
</j:jelly>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Display Base Table for Each Field
2+
3+
This code snippet demonstrates how to identify the base table where each field originates from in ServiceNow's table inheritance hierarchy.
4+
5+
## Functionality
6+
7+
The script uses `GlideRecordUtil` to retrieve all parent tables for a given table, then iterates through each field in a record to display which base table the field was defined in using the `getBaseTableName()` method from the GlideElement API.
8+
9+
## Use Case
10+
11+
This is particularly useful when working with extended tables to understand:
12+
- Which fields are inherited from parent tables
13+
- Which fields are defined locally on the current table
14+
- The complete table inheritance structure
15+
16+
## Example Output
17+
18+
For a table like `db_image`, the output shows each field name alongside its originating table:
19+
```
20+
Fields Base table
21+
sys_id sys_metadata
22+
sys_created_on sys_metadata
23+
image db_image
24+
name db_image
25+
...
26+
```
27+
28+
## Related Methods
29+
30+
- `getBaseTableName()` - Returns the name of the table where the field was originally defined
31+
- `GlideRecordUtil.getTables()` - Returns parent tables in the inheritance hierarchy
32+
- `GlideRecordUtil.getFields()` - Returns an array of all field names for a GlideRecord
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
var tableName = 'db_image';
2+
3+
var gru = new GlideRecordUtil();
4+
5+
var parentTables = gru.getTables(tableName);
6+
gs.print("Parent tables: " + parentTables);
7+
8+
var gr = new GlideRecord(tableName);
9+
gr.setlimit(1);
10+
gr.query();
11+
12+
if(gr.next()){
13+
var fieldNames = gru.getFields(gr);
14+
gs.print('Fields\t\tBase table');
15+
for (var i = 0; i < fieldNames.length; i++) {
16+
gs.print(fieldNames[i] + "\t\t" + gr[fieldNames[i]].getBaseTableName());
17+
}
18+
}
19+
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
(function executeRule(current, previous /*null when async*/) {
2+
3+
// Extract the first 3 characters of the budget currency code (e.g., "INR", "EUR")
4+
var currencyCode = current.budget_currency ? current.budget_currency.toString().substring(0, 3) : '';
5+
6+
// Convert the annual budget value to a float
7+
var amount = parseFloat(current.annual_budget);
8+
9+
// Validate input: If currency code is missing or amount is not a valid number, clear the USD field and exit
10+
if (!currencyCode || isNaN(amount)) {
11+
current.u_annual_budget_usd = '';
12+
return;
13+
}
14+
15+
// If the currency is already USD, no conversion needed — store the original amount
16+
if (currencyCode === 'USD') {
17+
current.u_annual_budget_usd = amount;
18+
return;
19+
}
20+
21+
// Check if the currency exists in the fx_currency table
22+
var currencyGR = new GlideRecord('fx_currency');
23+
currencyGR.addQuery('code', currencyCode);
24+
currencyGR.query();
25+
26+
// If currency is not found, clear the USD field and exit
27+
if (!currencyGR.next()) {
28+
current.u_annual_budget_usd = '';
29+
return;
30+
}
31+
32+
// Get the latest exchange rate for the selected currency from fx_rate table
33+
var fxGR = new GlideRecord('fx_rate');
34+
fxGR.addQuery('currency.code', currencyCode);
35+
fxGR.orderByDesc('sys_updated_on'); // Sort by most recent update
36+
fxGR.setLimit(1); // Limit to the latest record
37+
fxGR.query();
38+
39+
// If no exchange rate found, clear the USD field and exit
40+
if (!fxGR.next()) {
41+
current.u_annual_budget_usd = '';
42+
return;
43+
}
44+
45+
var rate = parseFloat(fxGR.getValue('rate')); // Exchange rate for selected currency
46+
47+
// Get the latest exchange rate for USD from fx_rate table
48+
var fxGR1 = new GlideRecord('fx_rate');
49+
fxGR1.addQuery('currency.code', 'USD');
50+
fxGR1.orderByDesc('sys_updated_on'); // Sort by most recent update
51+
fxGR1.setLimit(1); // Limit to the latest record
52+
fxGR1.query();
53+
54+
// If no USD exchange rate found, clear the USD field and exit
55+
if (!fxGR1.next()) {
56+
current.u_annual_budget_usd = '';
57+
return;
58+
}
59+
60+
var usdRate = parseFloat(fxGR1.getValue('rate')); // USD base rate
61+
62+
// Perform conversion only if both rates are valid and non-zero
63+
if (!isNaN(rate) && !isNaN(usdRate) && rate !== 0) {
64+
var convertedAmount = (amount / rate) * usdRate; // Convert to USD
65+
current.u_annual_budget_usd = convertedAmount; // Store the converted value
66+
} else {
67+
gs.info("Invalid exchange rate values");
68+
current.u_annual_budget_usd = '';
69+
}
70+
71+
})(current, previous);
72+
``
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
This script is designed to automatically convert the value of the Annual Budget field (annual_budget) from its original currency to USD. It uses the fx_currency and fx_rate tables to fetch the latest exchange rates and performs the conversion only when valid data is available.
2+
🔍 Key Features:
3+
4+
Field Focus: Converts the annual_budget field based on the currency specified in budget_currency.
5+
Validation: Ensures both the currency code and amount are valid before proceeding.
6+
Currency Check: If the currency is already USD, it bypasses conversion.
7+
Exchange Rate Lookup: Retrieves the most recent exchange rates for both the source currency and USD.
8+
Conversion Logic: Applies the formula
9+
USD Amount=(Original AmountSource Rate)×USD Rate\text{USD Amount} = \left(\frac{\text{Original Amount}}{\text{Source Rate}}\right) \times \text{USD Rate}USD Amount=(Source RateOriginal Amount​)×USD Rate
10+
Error Handling: Clears the USD field if any required data is missing or invalid.
11+
12+
This script ensures accurate and up-to-date currency conversion for budgeting purposes and is well-commented for maintainability and clarity.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
(function executeRule(current, previous /*null when async*/) {
2+
3+
4+
5+
// Only run if description has a value
6+
if (current.description) {
7+
var desc = current.description.toString();
8+
9+
10+
// Regex patterns for sensitive data
11+
var ccRegex = /\b\d{13,16}\b/g; // 13–16 continuous digits
12+
var ccSpaced = /\b(\d{4}[- ]?){3}\d{4}\b/g; // 4-4-4-4 with spaces/dashes
13+
var ssnRegex = /\b\d{3}-\d{2}-\d{4}\b/g; // US SSN
14+
var phoneRegex = /(\+?\d{1,2}[- ]?)?\(?\d{3}\)?[- ]?\d{3}[- ]?\d{4}/g; // phone
15+
16+
var masked = desc;
17+
18+
// Apply masking with messages
19+
if (ccRegex.test(desc)) {
20+
gs.addInfoMessage("Credit card pattern found → masking");
21+
masked = masked.replace(ccRegex, "****-****-****-****");
22+
}
23+
24+
if (ccSpaced.test(desc)) {
25+
gs.addInfoMessage("Spaced/dashed credit card pattern found → masking");
26+
masked = masked.replace(ccSpaced, "****-****-****-****");
27+
}
28+
29+
if (ssnRegex.test(desc)) {
30+
gs.addInfoMessage("SSN pattern found → masking");
31+
masked = masked.replace(ssnRegex, "***-**-****");
32+
}
33+
34+
if (phoneRegex.test(desc)) {
35+
gs.addInfoMessage("Phone number pattern found → masking");
36+
masked = masked.replace(phoneRegex, "**********");
37+
}
38+
39+
// If changes were made, update the description
40+
if (masked !== desc) {
41+
current.description = masked;
42+
gs.addInfoMessage("Final masked description: " + masked);
43+
gs.log("Masking rule triggered on record: " + current.number, "MaskingRule");
44+
} else {
45+
gs.addInfoMessage("No sensitive data detected, nothing masked.");
46+
}
47+
}
48+
49+
})(current, previous);
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
This script scans the description field of a record for patterns that resemble sensitive personal data and masks them to ensure privacy and compliance. It targets the following data types using regular expressions:
2+
3+
Credit Card Numbers: Detects both continuous digits (13–16 digits) and spaced/dashed formats (e.g., 1234-5678-9012-3456).
4+
Social Security Numbers (SSNs): Matches the standard US format (XXX-XX-XXXX).
5+
Phone Numbers: Identifies various formats including international and local styles.
6+
7+
If any of these patterns are found, the script replaces them with masked placeholders (e.g., ****-****-****-**** for credit cards) and updates the description field accordingly. It also logs messages to the system and displays info messages to notify users of the masking actions taken.

0 commit comments

Comments
 (0)