- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 02:13 AM
Hi Team ,
can anyone please help me on this requirment
Refer attached this is a confusing interface for the user - Please add an Approve and Reject button where the tick .
can anyone please provide steps to achieve this requirment
please provide configuration screenshots for better understanding .
@Ankur Bawiskar Please help me on this requriment with your solution
Thanks
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 06:29 AM
here is the working example, my buttons are at different place
You can try to adjust it as per your requirement
Script Include:
var ApprovalHandler = Class.create();
ApprovalHandler.prototype = {
initialize: function() {},
processApproval: function(approvalId, action) {
// Validate action
if (action != 'approved' && action != 'rejected') {
return { success: false, message: 'Invalid action' };
}
var gr = new GlideRecord('sysapproval_approver');
if (gr.get(approvalId)) {
// Check if the current user is the approver or a delegate
if (gr.approver != gs.getUserID()) {
var delegateUtil = new global.DelegationUtil();
if (!delegateUtil.isUserOrDelegate(gr.approver)) {
return { success: false, message: 'You are not authorized to approve this request' };
}
}
gr.state = action;
var result = gr.update();
if (result) {
// Optionally trigger workflow or other logic here
return { success: true, message: 'Approval updated successfully' };
} else {
return { success: false, message: 'Failed to update approval' };
}
} else {
return { success: false, message: 'Approval record not found' };
}
}
};
Widget
HTML:
<div ng-if="!data.isValid">
${Record not found}
</div>
<div ng-if="data.isValid">
<div class="panel panel-{{::options.color}} b">
<div class="panel-heading">
<h2 class="panel-title">${Approval request for {{::task.table}} {{::task.number.display_value}}}</h2>
</div>
<div class="panel-body">
<div ng-if="task.short_description">{{::task.short_description.display_value}}</div>
<div ng-if="task.opened_by"><label>${Opened by}</label> {{::task.opened_by.display_value}}</div>
<div ng-if="task.requested_by"><label>{{::task.requested_by_label}}</label> {{::task.requested_by.display_value}}</div>
<div ng-if="::data.approver"><label>${Approver}</label> {{::data.approver}}</div>
<div ng-if="task.start_date"><label>${Start}</label> {{::task.start_date.display_value}}</div>
<div ng-if="task.end_date"><label>${End}</label> {{::task.end_date.display_value}}</div>
<div ng-if="task.quantity">${Quantity} {{::task.quantity.display_value}}</div>
<div ng-if="task.price.value > 0"><label>${Price}</label> {{::task.price.display_value}}
<span ng-if="task.recurring_frequency.value != null"><label>${Recurring price}</label> {{::task.recurring_price.display_value}} {{task.recurring_frequency.display_value}}</span>
<label ng-if="task.quantity && task.quantity.value > 1"> ${each}</label>
</div>
<button ng-click="approve()" class="btn btn-success">Approve</button>
<button ng-click="reject()" class="btn btn-danger">Reject</button>
<div ng-if="data.items.length > 0">
<h3 class="h4">${Items in this Request}</h3>
<div ng-repeat="item in data.items">
<h4>
{{::item.short_description}}
</h4>
<div ng-if="item.price">${Price} {{::item.price}}
<span ng-if="item.recurring_price">${Recurring price} {{::item.recurring_price}} {{::item.recurring_frequency}}</span>
</div>
<sp-widget ng-if="item.variableSummarizerWidget" widget="item.variableSummarizerWidget"></sp-widget>
</div>
</div>
<sp-widget widget="data.variableSummarizerWidget"></sp-widget>
</div>
<sp-widget widget="data.ticketConversation"></sp-widget>
</div>
Client Controller:
function ($scope, $animate, $rootScope) {
var c = this;
$scope.$watch("data.task", function() {
$scope.task = $scope.data.task; // copy for shortcuts above
})
$scope.approve = function() {
c.server.get({
action: 'approved',
approvalId: c.data.sys_id
}).then(function(response) {
if (response.data.result.success) {
alert('Approved successfully!');
// Optionally reload or redirect
} else {
alert(response.data.result.message);
}
});
};
$scope.reject = function() {
c.server.get({
action: 'rejected',
approvalId: c.data.sys_id
}).then(function(response) {
if (response.data.result.success) {
alert('Rejected successfully!');
// Optionally reload or redirect
} else {
alert(response.data.result.message);
}
});
};
}
Server Side Script:
(function() {
// g_approval_form_request is for approval summarizer ACLs
// that let user read a record they need to approve. This global
// variable is then deleted at the bottom of the script
g_approval_form_request = true;
var gr = $sp.getRecord();
if (gr == null || !gr.isValid()) {
data.isValid = false;
return;
}
if (gr.getValue("approver") != gs.getUserID())
data.approver = gr.approver.getDisplayValue();
data.isValid = true;
var task = getRecordBeingApproved(gr);
if (task == null) {
data.isValid = false;
return;
}
var t = {};
t = $sp.getFieldsObject(task, 'number,short_description,opened_by,requested_by,start_date,end_date,quantity,price,recurring_price,recurring_frequency');
t.table = task.getLabel();
var items = [];
var idx = 0;
var itemsGR = new GlideRecord("sc_req_item");
itemsGR.addQuery("request", task.sys_id);
itemsGR.query();
while (itemsGR.next()) {
var item = {};
item.short_description = itemsGR.short_description.toString();
if (itemsGR.getValue("price") > 0)
item.price = itemsGR.getDisplayValue("price");
if (itemsGR.getValue("recurring_price") > 0) {
item.recurring_price = itemsGR.getDisplayValue("recurring_price");
item.recurring_frequency = itemsGR.getDisplayValue("recurring_frequency");
}
if (itemsGR) {
item.variables = new GlobalServiceCatalogUtil().getVariablesForTask(itemsGR, true);
item.variableSummarizerWidget = $sp.getWidget('sc-variable-summarizer', {'variables' : item.variables, 'toggle' : false, 'task': t.number.value});
}
items[idx] = item;
idx++;
}
data.items = items;
data.sys_id = gr.getUniqueValue();
t.requested_by_label = gs.getMessage('Requestor');
if(t.requested_by && t.requested_by.type== 'glide_date')
t.requested_by_label = t.requested_by.label;
data.task = t;
if (task) {
data.variables = new GlobalServiceCatalogUtil().getVariablesForTask(task, true);
data.variableSummarizerWidget = $sp.getWidget('sc-variable-summarizer', {'variables' : data.variables, 'toggle' : true, 'task': t.number.value});
}
function getRecordBeingApproved(gr) {
var approvalTargetRecord;
if (!gr.sysapproval.nil())
approvalTargetRecord = gr.sysapproval.getRefRecord();
else
approvalTargetRecord = gr.document_id.getRefRecord();
return (approvalTargetRecord.canRead()) ? approvalTargetRecord : null;
}
var ticketConversationOptions = {
placeholder: gs.getMessage("Type your message here..."),
placeholderNoEntries: gs.getMessage("Start a conversation..."),
btnLabel: gs.getMessage("Send")
};
if (options.use_approval_record_activity_stream === true ||
options.use_approval_record_activity_stream === "true") {
ticketConversationOptions.sys_id = gr.getUniqueValue();
ticketConversationOptions.table = gr.getRecordClassName();
ticketConversationOptions.title = gs.getMessage("Activity Stream for Approval");
} else {
ticketConversationOptions.sys_id = task.getUniqueValue();
ticketConversationOptions.table = task.getRecordClassName();
ticketConversationOptions.title = gs.getMessage("Activity Stream for {0}", task.getLabel());
}
data.ticketConversation = $sp.getWidget('widget-ticket-conversation', ticketConversationOptions);
delete g_approval_form_request;
if (input && input.action) {
var handler = new ApprovalHandler();
var result = handler.processApproval(input.approvalId, input.action);
data.result = result;
return;
}
})();
Output:
If my response helped please mark it correct and close the thread so that it benefits future readers.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 06:43 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 06:46 AM
@Ankur Bawiskar Is script include client callable ?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 06:58 AM
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 06:59 AM
you can update such that those buttons are gone when it's not requested
I believe I have answered your question with the correct outcome and you can enhance it from here.
Please mark my response as correct and close the thread.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
06-03-2025 09:26 AM
I believe I have answered your question and you can mark my response as correct and close the thread.
Ankur
✨ Certified Technical Architect || ✨ 9x ServiceNow MVP || ✨ ServiceNow Community Leader