Join the #BuildWithBuildAgent Challenge! Get recognized, earn exclusive swag, and inspire the ServiceNow Community with what you can build using Build Agent.  Join the Challenge.

Approval info Widget add close notes

EstebanlBetancu
Tera Contributor

Hello, everyone, I am looking for your help to solve this.

I cloned the approval info widget and I want to add a modal so I can add the closing notes. but I don't know how to send the information to the case.

I currently have this code:

HTML:

 

 

 

 

<div ng-if="c.data.isValid" class="panel panel-{{::c.options.color}} b">
  <div class="panel-heading">
    <h2 class="panel-title" ng-if="c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires your approval}</h2>
    <h2 class="panel-title" ng-if="!c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires approval <span ng-if="c.data.approverDisplay"> by {{c.data.approverDisplay}}}</span></h2>
    <h2 class="panel-title" ng-if="c.data.state == 'approved'">{{data.approvedMsg}}</h2>
    <h2 class="panel-title" ng-if="c.data.state == 'rejected'">{{data.rejectedMsg}}</h2>
  </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"></sn-time-ago></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-primary btn-question" ng-disabled="c.approvalInProgress" ng-click="c.action('approved')">${Approve}</button>
        <div class="spacer"></div>
        <button type="button" name="reject" class="btn btn-default btn-question" ng-disabled="c.approvalInProgress" ng-click="c.action('rejected')">${Reject}</button>
      </div>
    </form>
  </div>  
</div>

 

 

 

 



Client Script:

 

 

 

 

function ($scope, spUtil, spModal, spUIActionsExecuter) {
    var c = this;

    var ESIGNATURE = {
        "approved": "cbfe291147220100ba13a5554ee4904d",
        "rejected": "580f711147220100ba13a5554ee4904b"
    };

    // Observa cambios en registros específicos para reaccionar en tiempo real
    spUtil.recordWatch($scope, "sysapproval_approver", "state=requested^sys_id=" + c.data.sys_id);
    c.approvalInProgress = false;

    c.action = function (state) {
        var proceedWithAction = function () {
            if (c.data.esignature.e_sig_required) {
                var requestParams = {
                    username: c.data.esignature.username,
                    userSysId: c.data.esignature.userSysId,
                    notes: c.data.esignature.notes || "" // Incluye notas si están disponibles
                };
                spUIActionsExecuter.executeFormAction(ESIGNATURE[state], "sysapproval_approver", c.data.sys_id, [], "", requestParams).then(function (response) {
                    // Manejo de la respuesta exitosa
                }, function (error) {
                    // Manejo de errores
                    spUtil.addErrorMessage("Error al procesar la solicitud.");
                });
            } else {
                c.approvalInProgress = true;
                c.data.op = state;
                c.server.update().then(function (response) {
                    c.approvalInProgress = false;
                    if (!response.result.updateID) {
                        spUtil.addErrorMessage(c.data.actionPreventedMsg);
                    } else {
                        c.data.state = state;
                        var message = state === 'approved' ? c.data.approvedStatusMsg : c.data.rejectedStatusMsg;
                        spUtil.addInfoMessage(message);
                    }
                }, function (error) {
                    // Manejo de errores
                    c.approvalInProgress = false;
                    spUtil.addErrorMessage("Error al actualizar la solicitud.");
                });
            }
        };

        if (state === 'rejected') {
            // Solicita notas de cierre al rechazar
            spModal.prompt("Rechazo de Solicitud", "Por favor, ingresa las notas de cierre para el rechazo.").then(function (notes) {
                if (notes) {
                    c.data.esignature.notes = notes; // Asegura el manejo adecuado de las notas
                    proceedWithAction();
                } else {
                    console.log("Rechazo cancelado por el usuario.");
                }
            });
        } else {
            // Proceder inmediatamente con la aprobación
            proceedWithAction();
        }
    };
}

 

 

 

 


Server Script:

 

 

 

 

(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);
	var userApprovalAccess = gs.hasRole("approval_admin") || (gs.hasRole("approver_user") && data.isMine);
	
	var approverDisplay = gr.approver.getDisplayValue();
	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;
        console.log("input.op: " + input.esignature.notes);
        if (input.op === 'rejected' && input.esignature && input.esignature.notes) {
            gr.close_notes = input.esignature.notes;
        }
        
		data.updateID = gr.update();
		if (GlideStringUtil.nil(data.updateID)) {
			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();
	var record = getRecordBeingApproved(gr);
	data.label = record.getLabel();
	data.approvedStatusMsg = gs.getMessage("{0} has been approved", record.number);
	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();
	}
})();

 

 

 

 



3 REPLIES 3

Sumanth16
Kilo Patron

Hi @EstebanlBetancu ,

 

HTML:

<textarea id="comments" name="comments" rows="4" cols="30" ng-model="c.data.comments">
</textarea>

Server Side:

if (input && input.op && userApprovalAccess) {
gr.comments = input.comments;
}

In var field line,

use this 

var fields = $sp.getFields(gr, 'state,sys_created_on,comments');

 

use this below data.fields = fields;

var work = gr.comments.getJournalEntry(1);
var array = work.split(")");
data.comment = array[1];

Now,In comments we have got comment we entered


In HTML to display server side data use

Comment:<div>{{c.data.comment}}</div>

It will pass data from HTML to server-side.

 

 

If I could help you with your Query then, please hit the Thumb Icon and mark it as Correct !!

 

Thanks & Regards,

Sumanth Meda

EstebanlBetancu
Tera Contributor

is it possible to use the modal that i am putting? 

EstebanlBetancu
Tera Contributor

My SOLUTION:

<div ng-if="c.data.isValid" class="panel panel-{{::c.options.color}} b">
  <div class="panel-heading">
    <h2 class="panel-title" ng-if="c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires your approval}</h2>
    <h2 class="panel-title" ng-if="!c.data.isMine && (c.data.state == 'requested')">${This {{c.data.label}} requires approval <span ng-if="c.data.approverDisplay"> by {{c.data.approverDisplay}}}</span></h2>
    <h2 class="panel-title" ng-if="c.data.state == 'approved'">{{data.approvedMsg}}</h2>
    <h2 class="panel-title" ng-if="c.data.state == 'rejected'">{{data.rejectedMsg}}</h2>
  </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-primary btn-question" ng-disabled="c.approvalInProgress" ng-click="c.action('approved')">${Approve}</button>
        <div class="spacer"></div>
                <button type="button" name="reject" class="btn btn-default btn-question" ng-disabled="c.approvalInProgress" ng-click="c.reject_action('rejected')">${Reject}</button>
    </div>
    </form>
  </div>  
</div>

 
Client Script

function($scope, spUIActionsExecuter, spUtil, spModal) { 
    var c = this;

    var ESIGNATURE = {
        "approved": "cbfe291147220100ba13a5554ee4904d",
        "rejected": "580f711147220100ba13a5554ee4904b"
    };



    spUtil.recordWatch($scope, "sysapproval_approver", "state=requested^sys_id=" + c.data.sys_id);
    c.approvalInProgress = false;

    c.action = function(state) {

        if (c.data.esignature.e_sig_required) {
            var requestParams = {
                username: c.data.esignature.username,
                userSysId: c.data.esignature.userSysId
            };
            spUIActionsExecuter.executeFormAction(ESIGNATURE[state], "sysapproval_approver", c.data.sys_id, [], "", requestParams).then(function(response) {});
        } else {
            c.approvalInProgress = true;
            c.data.op = state;
            c.server.update().then(function() {
                c.approvalInProgress = false;
                if (!c.data.updateID) // update failed
                    spUtil.addErrorMessage(c.data.actionPreventedMsg);
                else {

                    c.data.state = state;
                }

            });
        }
    }

    //test
    c.reject_action = function(state) {
        spModal.prompt("Please enter the rejection reason. (required)").then(function(rejectReason) {
            $scope.data.op = "rejected";
            //$scope.data.target = id;
            $scope.data.comments = rejectReason;
            c.action(state);         
        });
			
    }



}



Server Client

(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);
	var userApprovalAccess = gs.hasRole("approval_admin") || (gs.hasRole("approver_user") && data.isMine);
	
	var approverDisplay = gr.approver.getDisplayValue();
	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;
        gr.comments = input.comments;

        // Buscar el ID del caso referenciado
        var caseID;
        if (!gr.sysapproval.nil()) {
            caseID = gr.sysapproval;
        } else {
            caseID = gr.document_id;
        }

        // Buscar en la tabla sc_req_item y actualizar close_notes
        var scReqItemGR = new GlideRecord("sc_req_item");
        if (scReqItemGR.get(caseID)) {
            scReqItemGR.close_notes = input.comments;
            scReqItemGR.update();
        } else {
            gs.error("No se encontró el registro en la tabla sc_req_item con el ID: " + caseID);
        }

        // Resto del código...
        console.log(input);

        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,comments');


	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();
	var record = getRecordBeingApproved(gr);
	var work = gr.comments.getJournalEntry(1);
	var array = work.split(")");
	data.comment = array[1];
	data.label = record.getLabel();
	data.approvedStatusMsg = gs.getMessage("{0} has been approved", record.number);
	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();
	}
})();