Delegate user can not approve or reject the request in the portal
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-28-2018 06:55 AM
Hello
I have a problem with user delegation.
User A declared user B as his delegate for approvals.
When user A receives a notification for an approval, then user B receives the same notification.
When user B goes in the portal to check its approvals, he can see the pending approval of the request but when he clicks on it, the buttons approve or reject do not appear so he can’t finalize the request.
Why does user B can’t approve the request as a delegator ?
Please check document joined for appropriate screenshots
Regards
Vanessa Heux
- Labels:
-
Service Portal Development
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-28-2018 08:20 AM
The last link seems to be interesting but I don't recognize where the replace proposed by adrianherdan should be done.
So I can't do anything.
I have looked in the widget where I found the approve or reject buttons.

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-28-2018 08:27 AM
You'd have to read down quite a bit and see the finalized code that he said works, but that's for the approvers widget itself. So you'd need to replace the code there with what they posted. So clone approvers widget, remove old code, paste in that code, add widget to the respective page, and should work out.
Please consider marking my reply as Helpful and/or Accept Solution, if applicable. Thanks!

- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎06-28-2018 11:02 AM
I've had to do this at before. You'll need to remove the Approval Info Widget from the "Approval Form" then create your own.
Here's the one we use;
HTML
<div ng-if="c.data.isValid" class="panel panel-{{::c.options.color}} b">
<div class="panel-heading">
<h4 class="panel-title" ng-if="c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires your approval}</h4>
<h4 class="panel-title" ng-if="!c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires approval <span ng-if="c.data.approver"> by {{c.data.approver}}}</span></h4>
<h4 class="panel-title" ng-if="c.data.state == 'approved'">${Approved} <sn-time-ago timestamp="::c.data.sys_updated_on" /></h4>
<h4 class="panel-title" ng-if="c.data.state == 'rejected'">${Rejected} <sn-time-ago timestamp="::c.data.sys_updated_on" /></h4>
</div>
<div class="panel-body">
<form ng-submit="$event.preventDefault()" class="form-horizontal">
<div ng-if="c.data.fields.length > 0">
<div ng-repeat="field in c.data.fields" class="m-b-xs" ng-if="field.value">
<label class="m-n">{{field.label}}</label>
<span ng-switch="field.type">
<div ng-switch-when="glide_date_time" title="{{field.display_value}}"><sn-time-ago timestamp="::field.value" /></div>
<div ng-switch-default >{{field.display_value}}</div>
</span>
</div>
</div>
<div ng-if="c.data.isMine && (c.data.state == 'requested')" class="question">
<button type="button" name="approve" class="btn btn-success btn-question" ng-click="c.action('approved')">${Approve}</button>
<div class="spacer"></div>
<button type="button" name="reject" class="btn btn-default btn-question" ng-click="c.action('rejected')">${Reject}</button>
</div>
</form>
</div>
</div>
CSS
.question {
text-align: center;
margin-top: 1em;
}
.spacer {
display:inline-block;
width:5%;
}
.btn-question {
width: 45%;
}
Server Script
(function() {
var gr = $sp.getRecord();
if (gr == null || !gr.isValid()) {
data.isValid = false;
return;
}
data.isValid = true;
//data.isMine = gr.getValue("approver") == gs.getUserID();
//data.isMine = getMyApprovals().toString().indexOf(gr.getValue("approver") >= 0);
data.isMine = (getMyApprovals().toString().indexOf(gr.getValue("approver")) >= 0);
data.approvers = getMyApprovals();
data.approval = gr.getValue("approver");
if (!data.isMine && !gr.approver.nil())
data.approver = gr.approver.getDisplayValue();
if (input && input.op) {
gr.state = input.op;
gr.update();
}
var fields = $sp.getFields(gr, 'state,sys_created_on');
if (gr.sys_mod_count > 0)
fields.push($sp.getField(gr, 'sys_updated_on'));
data.fields = fields;
data.state = gr.state.toString();
data.sys_updated_on = gr.sys_updated_on.toString();
data.sys_id = gr.getUniqueValue();
data.table = gr.getTableName();
data.label = getRecordBeingApproved(gr).getLabel();
function getRecordBeingApproved(gr) {
if (!gr.sysapproval.nil())
return gr.sysapproval.getRefRecord();
return gr.document_id.getRefRecord();
}
})();
Client Controller
function () {
var c = this;
c.action = function(state) {
c.data.op = state;
c.data.state = state;
c.server.update();
}
}
Demo Data
{
"data": {
"fields": [
{
"type": "glide_date_time",
"value": "2016-01-31T17:33:54+00:00",
"label": "Approval Example Label"
}
],
"state": "requested",
"label": "incident"
},
"options": {
"color": "default"
}
}
Good luck!
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
‎01-27-2022 05:16 PM
The information provided is indeed very helpful. I resolved the issue little differently in Quebec release. I made changes in only server script of 'Approval Info' OOTB widget. Thought of sharing it in case if anyone wants to try it.
Please refer // Customization Start in OOTB Widget and // Customization End in OOTB widget for customizations done.
(function() {
data.actionPreventedMsg = gs.getMessage("Update failed");
var gr = $sp.getRecord();
if (gr == null || !gr.isValid()) {
data.isValid = false;
return;
}
data.isValid = true;
data.isMine = isApprovalMine(gr);
// Customization Start in OOTB Widget
var delegateApproval = new ApprovalDelegationUtil().isMyApproval(gr);
//var userApprovalAccess = gs.hasRole("approval_admin") || (gs.hasRole("approver_user") && data.isMine);
var userApprovalAccess = gs.hasRole("approval_admin") || (gs.hasRole("approver_user") && data.isMine) || delegateApproval;
// Customization End in OOTB Widget
var approverDisplay = gr.approver.getDisplayValue();
// Customization Start in OOTB Widget
if (delegateApproval)
approverDisplay = gs.getUserDisplayName();
// Customization End in OOTB Widget
if (!data.isMine && approverDisplay)
data.approverDisplay = approverDisplay;
if (approverDisplay) {
data.approvedMsg = gs.getMessage("Approved by {0}", approverDisplay);
data.rejectedMsg = gs.getMessage("Rejected by {0}", approverDisplay);
} else {
data.approvedMsg = gs.getMessage("Approved");
data.rejectedMsg = gs.getMessage("Rejected");
}
if (input && input.op && userApprovalAccess) {
gr.state = input.op;
data.updateID = gr.update();
if (GlideStringUtil.nil(data.updateID)) {
// update failed so fetch again for correct values
gr = $sp.getRecord();
}
data.op = "";
}
var fields = $sp.getFields(gr, 'state,sys_created_on');
if (gr.sys_mod_count > 0)
fields.push($sp.getField(gr, 'sys_updated_on'));
data.fields = fields;
data.state = gr.state.toString();
data.sys_updated_on = gr.sys_updated_on.toString();
data.sys_id = gr.getUniqueValue();
data.table = gr.getTableName();
data.label = getRecordBeingApproved(gr).getLabel();
data.esignature = {
username: gs.getUserName(),
userSysId: gs.getUserID(),
e_sig_required: checkESig(gr)
};
function checkESig(approvalGR) {
var esigRegistryGR = new GlideRecord("e_signature_registry");
if (!esigRegistryGR.isValid())
return false;
var table = approvalGR.getValue("source_table");
if (!table)
table = approvalGR.sysapproval.sys_class_name;
if (!table)
return false;
esigRegistryGR.addQuery("enabled", "true");
esigRegistryGR.addQuery("table_name", table);
esigRegistryGR.query();
return esigRegistryGR.hasNext();
}
function getRecordBeingApproved(gr) {
if (!gr.sysapproval.nil())
return gr.sysapproval.getRefRecord();
return gr.document_id.getRefRecord();
}
})();