- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-06-2025 10:22 PM
Dear experts,
My client would like to have a bulk attest button just like the bulk approve button in the approval table where they can select multiple records in the list then in the list menu they have an approve button to approve all the things required in servicenow. So their requirements are without going into the attestation form and fill in the attestation form which only have two fields
1. Is the control implemented (Yes or No) - Mandatory
2. Explanation
They would like to have the ui action in the list menu which is approve where when click approve it will help them fill in the first question is yes and the explanation field is just leave it blank then changed the state of attestation form to complete. I have tried my own approach to create a new approve ui action list menu and a script include below:
UI Action Script:
function onBulkApprove() {
var selectedRecords = g_list.getChecked();
if (selectedRecords.length === 0) {
alert("Please select at least one record.");
return;
}
var ga = new GlideAjax('global.BulkAttestationProcessor');
ga.addParam('sysparm_name', 'processBulkAttestation');
ga.addParam('sysparm_sys_ids', selectedRecords.join(','));
ga.getXMLAnswer(function(response) {
alert(response); // Show confirmation
g_list.refresh(); // Refresh list
});
}
Script Include:
var BulkAttestationProcessor = Class.create();
BulkAttestationProcessor.prototype = Object.extendsObject(AbstractAjaxProcessor, {
processBulkAttestation: function() {
var sysIds = this.getParameter('sysparm_sys_ids').split(',');
var count = 0;
// Get the metric sys_id for the "Is the control implemented?" question
var metricGr = new GlideRecord('asmt_metric');
metricGr.addQuery('name', 'Is the control implemented?');
metricGr.query();
if (!metricGr.next()) {
return 'Metric "Is the control implemented?" not found.';
}
var metricSysId = metricGr.getUniqueValue();
for (var i = 0; i < sysIds.length; i++) {
var instanceId = sysIds[i];
var instanceGr = new GlideRecord('asmt_assessment_instance');
if (!instanceGr.get(instanceId)) continue;
// Check if metric result already exists
var resultGr = new GlideRecord('asmt_metric_result');
resultGr.addQuery('metric', metricSysId);
resultGr.addQuery('instance', instanceId);
resultGr.query();
var resultExists = false;
while (resultGr.next()) {
resultExists = true;
resultGr.setValue('actual_value', 1);
resultGr.update();
count++;
}
// If no result exists, create one manually
if (!resultExists) {
var newResult = new GlideRecord('asmt_metric_result');
newResult.initialize();
newResult.setValue('metric', metricSysId);
newResult.setValue('instance', instanceId);
newResult.setValue('actual_value', 1);
newResult.insert();
count++;
}
// Mark the instance as complete
instanceGr.setValue('state', 'complete');
instanceGr.update();
}
return count + " attestation(s) approved.";
}
});
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-06-2025 11:48 PM
Hi @ChuanYanF
You need to set the survey reponse in "asmt_assessment_instance_question" table.
I've modified your script and tested it in my PDI. It's working as expected. Please review and modify as required.
UI action:
function onBulkApprove() {
var selectedRecords = g_list.getChecked();
if (selectedRecords.length === 0) {
alert("Please select at least one record.");
return;
} else {
var ga = new GlideAjax('BulkAttestationProcessor');
ga.addParam('sysparm_name', 'processBulkAttestation');
ga.addParam('sysparm_sys_ids', selectedRecords);
ga.getXMLAnswer(function(response) {
alert(response); // Show confirmation
g_list.refresh(); // Refresh list
});
}
}
Script include:
var BulkAttestationProcessor = Class.create();
BulkAttestationProcessor.prototype = Object.extendsObject(AbstractAjaxProcessor, {
processBulkAttestation: function() {
var sysIds = this.getParameter('sysparm_sys_ids').split(',');
var count = 0;
// Get the metric sys_id for the "Is the control implemented?" question
var metricGr = new GlideRecord('asmt_metric');
metricGr.addQuery('name', 'Is the control implemented?');
metricGr.query();
if (!metricGr.next()) {
return 'Metric "Is the control implemented?" not found.';
} else {
var metricSysId = metricGr.getUniqueValue();
}
for (var i = 0; i < sysIds.length; i++) {
var instanceId = sysIds[i];
var instanceGr = new GlideRecord('asmt_assessment_instance');
if (!instanceGr.get(instanceId)) continue;
// Check if metric result already exists
var resultGr = new GlideRecord('asmt_assessment_instance_question'); //UPDATED
resultGr.addQuery('metric', metricSysId);
resultGr.addQuery('instance', instanceId);
resultGr.query();
var resultExists = false;
while (resultGr.next()) {
resultExists = true;
resultGr.setValue('value', 1);
resultGr.update();
count++;
}
// Mark the instance as complete
instanceGr.setValue('state', 'complete');
instanceGr.update();
}
return count + " attestation(s) approved.";
},
type: 'BulkAttestationProcessor'
});
Regards,
Siva
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-07-2025 12:37 AM
Hi Siva, really appreciate your help on this, but I still face a minor problem. So I have created the script include on global application and the asmt_instance is actually under GRC : Profiles, but I have allowed to all application scopes and I renamed the UI Action script to below: which stated the global.BulkAttestationProcessor because initially when I used your script it says access blocks for sn_grc: something like that, but after I renamed it it says null as below
function onBulkApprove() {
var selectedRecords = g_list.getChecked();
if (selectedRecords.length === 0) {
alert("Please select at least one record.");
return;
} else {
var ga = new GlideAjax('global.BulkAttestationProcessor');
ga.addParam('sysparm_name', 'processBulkAttestation');
ga.addParam('sysparm_sys_ids', selectedRecords);
ga.getXMLAnswer(function(response) {
alert(response); // Show confirmation
g_list.refresh(); // Refresh list
});
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-07-2025 12:46 AM
@ChuanYanF Everything looks good in the above script.
Just verify the script inlcude.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-07-2025 12:51 AM
Hi Siva, yes but I dont know why is just the access to this script include is blocked, this is my script include set up
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-07-2025 01:02 AM
@ChuanYanF I've created both the UI action and script include in the Global scope. Have you tried logging some messages inside the script include to verify if it's being called by the client script?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
05-07-2025 12:39 AM
If I just follow the script u gave me it shows this error