Service Portal:OOB Approval widget

gomathyshankar
Tera Contributor

Hi,

How to add the comments field in the OOB Approval widget and make it mandatory when the approvers rejects it.

1 ACCEPTED SOLUTION

Hi Selva,



Use the below and it wil work ( we have to change both client and server to update user comments in approval table)



Highlighted are the changes



Client controller:


function ($scope, spUtil, snRecordWatcher,spModal) {



  if ($scope.options.portal == true || $scope.options.portal == 'true') {


      $scope.contentColClass = "col-xs-12";


  $scope.options.portal = true;


  } else {


  $scope.options.portal = false;


  $scope.contentColClass = "col-sm-9";


  }




  $scope.data.op = "";


  snRecordWatcher.initList("sysapproval_approver", "state=requested^approver=" + window.NOW.user_id);




  function get() {


      spUtil.update($scope);


  }




  $scope.$on('record.updated', function(name, data) {


  get();


  })




  $scope.approve = function(id) {


      $scope.data.op = "approved";


      $scope.data.target = id;


      get();


  }




  $scope.reject = function(id) {


    c.onPrompt(id);


  }


c.onPrompt = function(id) {  


                spModal.open({  


                      title: 'Give me a comment',  


                      message: 'Your comment please?',  


                      input: true,  


                      value: c.comment  


              }).then(function(comment) {  


                      c.comment = comment;  


  if(comment)


  {


                      $scope.data.comment = comment;  


  $scope.data.op = "rejected";


  $scope.data.target = id;


  get();


  }


              })  


      }


}



Server side:


Replace


if (input && input.op) {


  var app = new GlideRecord("sysapproval_approver");


  if (app.get(input.target)) {


      app.state = input.op;


      app.update();


  }



With



if (input && input.op) {



  if(input.op == 'approved')


  {


  var app = new GlideRecord("sysapproval_approver");


  if (app.get(input.target)) {


      app.state = input.op;


      app.update();


  }


  }


  else if(input.op == 'rejected' && input.comment)


  {


  var app = new GlideRecord("sysapproval_approver");


  if (app.get(input.target)) {


    app.comments = input.comment;


      app.state = input.op;


      app.update();


  }


  }




Thanks and regards


Swamy


View solution in original post

38 REPLIES 38

I got this working.   I put the code back so approvals do not have a comment, but rejections do.   Below is the code I have in the widget.



HTML


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


<div class="panel panel-{{::options.color}} b">


  <div class="panel-heading">


      <h4 class="panel-title"><fa ng-if="::options.glyph.length" name="{{::options.glyph}}" class="m-r-sm" />${My Approvals}</h4>


      <p style="float:right;margin-top:-10px">


          <!-- <a ng-click="changeSort('name')" style="cursor:pointer;">Sort By: item<span class="fa fa-caret-up fa-lg" style="display:none;"></span><span class="fa fa-caret-down fa-lg" style="display:none;"></span></a><a ng-click="changeSort('number')" style="cursor:pointer;padding-left:3px;">Sort by: Number</a> -->


        </p>


  </div>


  <div class="panel-body">


      <div ng-if="data.approvals.length == 0">


          ${You have no pending approvals}


      </div>


      <div ng-repeat="approval in data.approvals" class="sp-approval m-b">


          <div class="row">


              <div ng-class="contentColClass">


                  <div ng-if="approval.task.number || approval.task.short_description">


                      <a ng-href="?id=approval&table=sysapproval_approver&sys_id={{::approval.sys_id}}" title="{{data.ViewApprovalPageMsg}}">


                          <span ng-if="approval.task.number">{{::approval.task.number}}</span>


                          <span ng-if="approval.task.number && approval.task.short_description"> - </span>


                          <span ng-if="approval.task.short_description">{{::approval.task.short_description}}</span>


                      </a>


                  </div>


                  <div ng-if="approval.task.opened_by"><label>${Requestor}</label> {{::approval.task.opened_by}}</div>


                  <div ng-if="approval.task.start_date"><label>${Start}</label> {{::approval.task.start_date}}</div>


                  <div ng-if="approval.task.end_date"><label>${End}</label> {{::approval.task.end_date}}</div>


                  <div ng-if="approval.task.price"><label>${Price}</label> {{::approval.task.price}}


                      <span ng-if="approval.task.recurring_price"><label>${Recurring price}</label> {{::approval.task.recurring_price}} {{::approval.task.recurring_frequency}}</span>


                  </div>


                  <div ng-if="approval.items.length == 1">


                      <div ng-repeat="item in approval.items">


                          <div ng-if="item.variables.length > 0" ng-init="variable_toggle=false">


                              <a href="javascript:void(0)" ng-click="variable_toggle = !variable_toggle">


                                  <span class="glyphicon"


                                              ng-class="{'glyphicon-chevron-down': !variable_toggle, 'glyphicon-chevron-up': variable_toggle}">


                                  </span>


                                  ${Options}


                              </a>


                              <div ng-repeat="variable in item.variables" ng-if="variable_toggle">


                                  <label class="text-muted">{{::variable.label}}</label>


                                  <div>{{::variable.display_value}}</div>


                              </div>


                          </div>


                      </div>


                  </div>




                  <div ng-if="approval.variables.length > 0" ng-init="variable_toggle=false">


                      <a href="javascript:void(0)" ng-click="variable_toggle = !variable_toggle">


                          <span class="glyphicon"


                                      ng-class="{'glyphicon-chevron-down': !variable_toggle, 'glyphicon-chevron-up': variable_toggle}">


                          </span>


                          ${Options}


                      </a>


                      <div ng-repeat="variable in approval.variables" ng-if="variable_toggle">


                          <label>{{::variable.label}}</label>


                          <div>{{::variable.display_value}}</div>


                      </div>


                  </div>


              </div>




              <div ng-if="!options.portal" class="col-sm-3">


                  <button name="approve" ng-if="approval.state == 'requested'" class="btn btn-primary btn-block" style="border-width:1px;" ng-click="approve(approval.sys_id);">${Approve}</button>


                  <button name="reject" ng-if="approval.state == 'requested'" class="btn btn-default btn-block" ng-click="reject(approval.sys_id);">${Reject}</button>


                  <button ng-if="approval.state == 'approved'" class="btn btn-success btn-block">{{approval.stateLabel}}</button>


                  <button ng-if="approval.state == 'rejected'" class="btn btn-danger btn-block">{{approval.stateLabel}}</button>


                  <button ng-if="approval.state != 'requested'" class="btn btn-default btn-block" style="visibility:hidden">{{approval.stateLabel}}</button>


              </div>


              <div ng-if="options.portal && approval.state == 'requested'" class="col-xs-6">


                  <button name="reject" class="btn btn-default btn-block" ng-click="reject(approval.sys_id);">${Reject}</button>


              </div>


              <div ng-if="options.portal && approval.state == 'requested'" class="col-xs-6">


                  <button name="approve" class="btn btn-primary btn-block" ng-click="approve(approval.sys_id);">${Approve}</button>


              </div>


              <div ng-if="options.portal && approval.state != 'requested'" class="col-xs-12">


                  <button ng-if="approval.state == 'approved'" class="btn btn-success btn-block">{{approval.stateLabel}}</button>


                  <button ng-if="approval.state == 'rejected'" class="btn btn-danger btn-block">{{approval.stateLabel}}</button>


              </div>


          </div>        


      </div>




CLIENT SCRIPT


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


function ($scope, spUtil, snRecordWatcher,$window,$location,spModal,$uibModal) {


  var c = this;


  if ($scope.options.portal == true || $scope.options.portal == 'true') {


      $scope.contentColClass = "col-xs-12";


  $scope.options.portal = true;


  } else {


  $scope.options.portal = false;


  $scope.contentColClass = "col-sm-9";


  }


  $scope.data.op = "";


  snRecordWatcher.initList("sysapproval_approver", "state=requested^approver=" + window.NOW.user_id);


  function get() {


      spUtil.update($scope);


  }


  $scope.$on('record.updated', function(name, data) {


  get();


  })


  $scope.approve = function(id) {  


      $scope.data.op = "approved";


      $scope.data.target = id;


      get();


  }



/* $scope.approve = function(id) {


        c.onPrompta(id);



  }


  c.onPrompta = function(id) {


                spModal.open({


                      title: 'Approval Comment',


                      message: 'Please provide an approval comment',


                      input: true,


                      value: c.comment


              }).then(function(comment) {


                      c.comment = comment;


  if(comment)


  {


                      $scope.data.comment = comment;


  $scope.data.op = "approved";


  $scope.data.target = id;


  get();


c.comment='';


  }


              })


      } */



  spUtil.recordWatch($scope, c.options.table, c.options.filter);


  $scope.reject = function(id) {


        c.onPromptr(id);



  }


  c.onPromptr = function(id) {


                spModal.open({


                      title: 'Rejection Comment',


                      message: 'Please a reason for rejection',


                      input: true,


                      value: c.comment


              }).then(function(comment) {


                      c.comment = comment;


  if(comment)


  {


                      $scope.data.comment = comment;


  $scope.data.op = "rejected";


  $scope.data.target = id;


  get();


c.comment='';


  }


              })


      }


}




SERVER SCRIPT


>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


if (input && input.op) {



  /* if(input.op == 'approved' && input.comment) */


  if(input.op == 'approved')


{


  var app = new GlideRecord("sysapproval_approver");


  if (app.get(input.target)) {


    /* app.comments = input.comment; */


      app.state = input.op;


      app.update();


  }


  }



  else if(input.op == 'rejected' && input.comment)


  {


  var app = new GlideRecord("sysapproval_approver");


  if (app.get(input.target)) {


    app.comments = input.comment;


      app.state = input.op;


      app.update();


  }


  }



}


options.table = 'sysapproval_approver';


options.filter = 'approver='+gs.getUserID();




data.ViewApprovalPageMsg = gs.getMessage("View approval page");


var recordIdx = 0;


var gr = new GlideRecord('sysapproval_approver');


gr.setLimit(50);


var qc1 = gr.addQuery("state", "requested");


if (input)


  qc1.addOrCondition("sys_id", "IN", input.ids);




gr.addQuery("approver", gs.getUserID());


gr.orderBy("sys_created_on");


gr.query();




var approvals = [];


var ids = [];


while (gr.next()) {


  var task = getRecordBeingApproved(gr);


  recordIdx++;


  if (!task.isValidRecord())


  continue;


  //if (recordIdx == 4)


  // break;


  ids.push(gr.getUniqueValue());


  var t = {};


  t.number = task.getDisplayValue();


  t.short_description = task.short_description.toString();


  if (task.isValidField("opened_by") && !task.opened_by.nil())


    t.opened_by = task.opened_by.getDisplayValue();




  // requestor >> opener


  if (task.isValidField("requested_by") && !task.requested_by.nil())


    t.opened_by = task.requested_by.getDisplayValue();




  t.start_date = task.start_date.toString();


  t.end_date = task.end_date.toString();


  t.table = task.getLabel();


  if (task.getValue("price") > 0)


    t.price = task.getDisplayValue("price");




  if (task.getValue("recurring_price") > 0)


    t.recurring_price = task.getDisplayValue("recurring_price");




  t.recurring_frequency = task.getDisplayValue("recurring_frequency");




  var items = [];


  var idx = 0;


  var itemsGR = new GlideRecord("sc_req_item");


  itemsGR.addQuery("request", task.sys_id);


  itemsGR.query();


  if (itemsGR.getRowCount() > 1)


      t.short_description = itemsGR.getRowCount() + " requested items";


  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.getRowCount() == 1) {


          item.variables = $sp.getRecordVariablesArray(itemsGR);


          t.short_description = itemsGR.short_description.toString();


      }


      items[idx] = item;


      idx++;


  }


  var j = {};


  j.sys_id = gr.getUniqueValue();


  j.table = gr.getRecordClassName();


  j.task = t;


  if (task)


      j.variables = $sp.getRecordVariablesArray(task);


  j.items = items;


  j.state = gr.getValue("state");


  j.stateLabel = gr.state.getDisplayValue();


  approvals.push(j);


}


data.ids = ids;


data.approvals = approvals;




function getRecordBeingApproved(gr) {


  if (!gr.sysapproval.nil())


      return gr.sysapproval.getRefRecord();




  return gr.document_id.getRefRecord();


}


Did anyone figure out why the comment is being copied multiple times?


bob_beck 's is the best solution I found so far. I am a bit surprised the comment on rejection is not the OOB solution.


And I would like to find out as well why the comments are duplicated. Can't use it this way, because multiple emails will be sent for every comment added.



harel


Hi Harel,

 

Do you have any solution for "comment is being copied multiple times"? if so please share your solution. Thank you.

 

Regards,

Raj

hi

 

Yes, have a look below at adrianherdan 's response. It solved the problem.

 

harel