I want to share my experience related to a specific business requirement in ServiceNow HR.
To complete any HR task, you expect the "Effective Date" to be populated first. For such cases, we typically write a "Before Update" business rule with current.setAbort(true);
The HR Task table has an out-of-the-box UI action called "Closed Complete" However, if you have any "Before Update" business rules to validate specific conditions, this out-of-the-box UI action will validate the business rules, but it will not show any error messages.
To provide a practical example, let’s assume an "Effective Date" field exists in the HR case.
To ensure that the "Closed Complete" button validates all business rules before proceeding with the form update, I customized the UI action "Closed Complete." The customized action will evaluate all the business rules, and if they pass, it will proceed with the update; otherwise, it will display errors from the rules.
A. Here is a Business Rule validation example:
B. Here is my customized "Closed Complete" UI action script:
function closeComplete() {var sysId = typeof rowSysId == 'undefined' || rowSysId == null ? g_form.getUniqueValue() : rowSysId;/* Customization Starts Here *//* Purpose: Validate the Before Update Business Rules First */validateAndSubmit();function validateAndSubmit() {// Check if form validation flag is already set to true, if yes, allow submissionif (g_scratchpad.isFormValid) {return true;}var ga = new GlideAjax('sn_hr_core.positionUtils');ga.addParam('sysparm_name', 'validateTask');ga.addParam('sys_id', sysId);ga.getXMLAnswer(function(response) {console.log('HR Task Validation Response ----'+response);if (response != 'pass') {g_scratchpad.isFormValid = false;return false;} else {g_scratchpad.isFormValid = true;showModalDialog();}});return false; // Prevent default form submission}/* Customization Ends Here */function showModalDialog() { //Custom//OOB Code (Out of the box):ScriptLoader.getScripts('sn_hr_core.utils_ui.jsdbx', function() {getGlideRecord("sn_hr_core_task", sysId, promptDialog);});function promptDialog(taskGr) {var dialogClass = GlideModal ? GlideModal : GlideDialogWindow;var dialog = new dialogClass('sn_hr_core_HR Task Comment Dialog');dialog.setTitle(getMessage('Provide a summary of the work performed'));dialog.setPreference('sysparm_task_sys_id', sysId);dialog.setPreference('sysparm_ok_method_name', 'closeCompleteTask');dialog.setPreference('sysparm_is_comment', 'false');dialog.setPreference('sysparm_task_table', 'sn_hr_core_task');dialog.on('hrTaskComentDialogSucess', function() {dialog.destroy();gsftSubmit(null, g_form.getFormElement(), 'sysverb_update');});dialog.render();return;}}}//OOB Code (Out of the box)if (typeof window == 'undefined')serverClose();//OOB Code (Out of the box)function serverClose() {if (current.work_end.nil())current.work_end = new GlideDateTime().getDisplayValue();current.state = 3;current.update();action.setRedirectURL(current);}
C. Here is my newly written script to include:
The method to evaluate business rules when the "Closed Complete" action is triggered:
var positionUtils = Class.create();positionUtils.prototype = Object.extendsObject(global.AbstractAjaxProcessor, {validateTask: function() {var result = 'pass'; // Default to 'pass'var hasFalseEvaluatorResult = false; // Flag to track if any evaluator result is falsevar sysId = this.getParameter('sys_id');var grHRTask = new GlideRecord('sn_hr_core_task');if (grHRTask.get(sysId)) {var errors = [];var brs = new GlideRecord('sys_script');brs.addEncodedQuery("active=true^collection=sn_hr_core_task^when=before^action_update=true^filter_conditionLIKEstateCHANGESTO3");brs.query();while (brs.next()) {// gs.info('Business Rule Validation----' + brs.getValue('name'));try {var script = brs.script;// gs.info(script);var evaluator = new GlideScopedEvaluator();evaluator.putVariable('current', grHRTask);var evaluatorResult = evaluator.evaluateScript(brs, 'script', script);gs.info('Business Rule' + brs.getValue('name') + 'Validation Result-----' + evaluatorResult);if (evaluatorResult == 'false') { // Check if the evaluator result is falsehasFalseEvaluatorResult = true;}} catch (e) {errors.push(e.message);}}if (errors.length > 0) {result = errors.join(', ');}}gs.info('hasFalseEvaluatorResult------' + hasFalseEvaluatorResult)// Set the final result based on the flagif (hasFalseEvaluatorResult) {result = 'fail';}return result;},type: 'positionUtils'});


