Name
sn_hr_core.hr_ApprovalUtil
Description
Provides utility for HR approvals and subflows.
Script
var hr_ApprovalUtil = Class.create();
hr_ApprovalUtil.prototype = {
type: 'hr_ApprovalUtil'
};
hr_ApprovalUtil.WORKFLOW_ID = '8de6490c53032200d901a7e6a11c0838';
hr_ApprovalUtil.checkApprovalParameters = function(caseGr, workflow) {
var serviceActivity = workflow.variables.service_activity_sys_id;
var leActivity = workflow.variables.le_activity_sys_id;
var adhocApprovers = workflow.variables.adhoc_approvers;
var waitFor = workflow.variables.wait_for;
var onRejection = workflow.variables.on_rejection;
if (serviceActivity)
hr_ApprovalUtil.getServiceActivityParameters(serviceActivity, workflow);
else if (leActivity)
hr_ApprovalUtil.getLEActivityParameters(leActivity, workflow);
else if (adhocApprovers) {
workflow.scratchpad.approvalUsers = adhocApprovers;
workflow.scratchpad.approval_accept_option = waitFor || 'first_response';
workflow.scratchpad.approval_reject_option = onRejection || 'close_case';
workflow.scratchpad.missing_some_approvers = 'skip';
workflow.scratchpad.missing_all_approvers = 'substitute';
} else
hr_ApprovalUtil.getHRServiceParameters(caseGr, workflow);
return !hr_ApprovalUtil.noApproversSet(workflow);
};
hr_ApprovalUtil.noApproversSet = function (workflow) {
var noOptions = gs.nil(workflow.scratchpad.approvalOptions);
var noGroups = gs.nil(workflow.scratchpad.approvalGroups);
var noUsers = gs.nil(workflow.scratchpad.approvalUsers);
return noOptions && noGroups && noUsers;
};
hr_ApprovalUtil.getServiceActivityParameters = function(activityId, workflow) {
var grSA = new GlideRecord('sn_hr_core_service_activity');
if (grSA.get(activityId)) {
workflow.scratchpad.approvalOptions = grSA.approval_options.toString();
workflow.scratchpad.approvalGroups = grSA.approver_groups.toString();
workflow.scratchpad.approvalUsers = grSA.approver_users.toString();
workflow.scratchpad.approval_accept_option = grSA.approval_accept_option || 'first_response';
workflow.scratchpad.approval_reject_option = grSA.approval_reject_option || 'close_case';
workflow.scratchpad.missing_some_approvers = grSA.missing_some_approvers || 'skip';
workflow.scratchpad.missing_all_approvers = grSA.missing_all_approvers || 'substitute';
}
};
hr_ApprovalUtil.getLEActivityParameters = function(activityId, workflow) {
var grLA = new GlideRecord('sn_hr_le_activity');
if (grLA.get(activityId)) {
workflow.scratchpad.approvalOptions = grLA.approvers.toString();
workflow.scratchpad.approvalGroups = grLA.approver_groups.toString();
workflow.scratchpad.approvalUsers = grLA.approver_users.toString();
workflow.scratchpad.approval_accept_option = grLA.approval_accept_option || 'anyone';
workflow.scratchpad.approval_reject_option = grLA.approval_reject_option || 'reapprove';
workflow.scratchpad.missing_some_approvers = grLA.missing_some_approvers || 'skip';
workflow.scratchpad.missing_all_approvers = grLA.missing_all_approvers || 'substitute';
}
};
hr_ApprovalUtil.getHRServiceParameters = function(caseGr, workflow) {
// set fields to mimic the OOB functionality of Jakarta
if (caseGr.hr_service.approval_options) {
workflow.scratchpad.approvalOptions = caseGr.hr_service.approval_options.toString();
workflow.scratchpad.approval_accept_option = 'first_response';
// approval subflow in Jakarta returns "rejected" and lets caller decide how to handle it
workflow.scratchpad.approval_reject_option = 'legacy';
}
workflow.scratchpad.insufficient_data_is_an_option = true;
};
hr_ApprovalUtil.approverCount = function(caseGr, workflow) {
workflow.scratchpad.approvers = [];
workflow.scratchpad.missingApprovers = [];
if (workflow.scratchpad.approvalOptions)
hr_ApprovalUtil._getApproversFromOptions(caseGr, workflow);
if (workflow.scratchpad.approvalGroups)
hr_ApprovalUtil._getApproversFromGroups(workflow);
if (workflow.scratchpad.approvalUsers)
hr_ApprovalUtil._getApproversFromUsers(workflow);
workflow.scratchpad.missingApprovers.sort();
return workflow.scratchpad.approvers.length;
};
hr_ApprovalUtil.missingApprovers = function(caseGr) {
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGr);
return approvalContext.scratchpad.missingApprovers;
};
hr_ApprovalUtil._getApproversFromOptions = function(caseGr, workflow) {
var gr = new GlideRecord('sn_hr_core_service_approval_option');
gr.addActiveQuery();
gr.addQuery('sys_id', 'IN', workflow.scratchpad.approvalOptions);
gr.query();
while (gr.next()) {
var glideEle = caseGr.getElement(gr.approval_assign_to);
if (glideEle) {
var refTo = glideEle.getReferenceTable();
var rootTable = new GlideTableHierarchy(refTo).getRoot();
switch (rootTable) {
case 'sys_user':
if (hr_ApprovalUtil.isValidUser(glideEle))
workflow.scratchpad.approvers.push(glideEle.toString());
else
workflow.scratchpad.missingApprovers.push(String(gr.name));
break;
case 'sys_user_group':
if (hr_ApprovalUtil.isValidGroup(glideEle))
workflow.scratchpad.approvers.push(glideEle.toString());
else
workflow.scratchpad.missingApprovers.push(String(gr.name));
break;
}
} else
workflow.scratchpad.missingApprovers.push(String(gr.name));
}
};
hr_ApprovalUtil._getApproversFromGroups = function(workflow) {
var approverGroups = String(workflow.scratchpad.approvalGroups).split(',');
for (var i = 0; i < approverGroups.length; i++) {
if (hr_ApprovalUtil.isValidGroup(approverGroups[i]))
workflow.scratchpad.approvers.push(approverGroups[i]);
else {
var group = new GlideRecord('sys_user_group');
group.get(approverGroups[i]);
workflow.scratchpad.missingApprovers.push(String(group.name));
}
}
};
hr_ApprovalUtil._getApproversFromUsers = function(workflow) {
var approverUsers = String(workflow.scratchpad.approvalUsers).split(',');
for (var j = 0; j < approverUsers.length; j++) {
if (hr_ApprovalUtil.isValidUser(approverUsers[j]))
workflow.scratchpad.approvers.push(approverUsers[j]);
else {
var grUser = new GlideRecord('sys_user');
grUser.get(approverUsers[j]);
workflow.scratchpad.missingApprovers.push(String(grUser.name));
}
}
};
hr_ApprovalUtil.isValidGroup = function(groupId) {
var grMember = new GlideRecord('sys_user_grmember');
grMember.addQuery('user.active', 'true');
grMember.addQuery('group', groupId);
grMember.setLimit(1);
grMember.query();
return grMember.hasNext();
};
hr_ApprovalUtil.isValidUser = function(userId) {
var grUser = new GlideRecord('sys_user');
grUser.addQuery('sys_id', userId);
grUser.addActiveQuery();
grUser.query();
return grUser.hasNext();
};
/*------------- Rejection option methods -------------*/
hr_ApprovalUtil._getStage = function(approvalContext) {
var stage = new GlideRecord("wf_stage");
if (stage.get(approvalContext.stage))
return stage.value;
else
return null;
};
hr_ApprovalUtil.isReapprovalAuthorized = function(caseGr) {
if (!new hr_Delegation().isAssignedOrDelegated(caseGr))
return false;
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGr);
return approvalContext != null && hr_ApprovalUtil._getStage(approvalContext) == 'awaiting_reapproval';
};
hr_ApprovalUtil.rerequestCaseApproval = function(caseGr) {
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGr);
new global.Workflow().broadcastEvent(approvalContext.sys_id, 'sn_hr_core.request_reapproval');
gs.addInfoMessage(gs.getMessage('Approvals have been re-requested'));
};
hr_ApprovalUtil.isSubstituteApprovers = function(caseGr) {
if (!new hr_Delegation().isAssignedOrDelegated(caseGr))
return false;
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGr);
var result = approvalContext != null && hr_ApprovalUtil._getStage(approvalContext) == 'substitute_approvers';
return result;
};
hr_ApprovalUtil.getApprovalSubflowsForCase = function(grCase) {
var wfContext = new global.Workflow().getRunningFlows(grCase);
//Find running context for 'HR Case Approval Subflow'
while (wfContext.next()) {
if (wfContext.workflow == hr_ApprovalUtil.WORKFLOW_ID)
return wfContext;
}
return null;
};
hr_ApprovalUtil.caseRejected = function(caseGr) {
var approval = new GlideRecord("sysapproval_approver");
approval.addQuery("sysapproval", current.sys_id);
approval.addQuery("state", "rejected");
approval.addQuery("wf_activity", "!=", "");
approval.setLimit(1);
approval.query();
return approval.hasNext();
};
hr_ApprovalUtil.disassociateApprovalsFromWorkflow = function(grCase) {
var approvalGr = new GlideRecord("sysapproval_approver");
approvalGr.addQuery("sysapproval", grCase.getUniqueValue());
approvalGr.addQuery('wf_activity.workflow_version.workflow', hr_ApprovalUtil.WORKFLOW_ID);
approvalGr.addQuery("state", "!=", "cancelled");
approvalGr.query();
while (approvalGr.next()) {
approvalGr.setValue('wf_activity', "");
approvalGr.update();
}
};
/*
* Returns list of missing approvers defined on approval HR service activity
*
* @param
* caseID: HR case sys_id string value
*
* @returns
* array list of missing approvers defined on approval HR service activity
*/
hr_ApprovalUtil.getMissingApproversOnCase = function(caseID) {
var substituteApproverGR = new GlideRecord('sn_hr_core_substitute_approver');
substituteApproverGR.addNotNullQuery('missing_approver');
substituteApproverGR.addQuery('hr_case', caseID);
substituteApproverGR.addQuery('approval_triggered', false);
substituteApproverGR.orderBy('missing_approver');
substituteApproverGR.query();
var missingApprovers = [];
while (substituteApproverGR.next()) {
var missingApprover = substituteApproverGR.getValue('missing_approver');
missingApprovers.push(missingApprover);
}
return missingApprovers;
};
/*
* Returns boolean true if atleast one approver is set for HR case
*
* @param
* caseID: HR case sys_id string value
*
* @returns
* boolean true if atleast one approver is set false otherwise
*/
hr_ApprovalUtil.approverSetForCase = function(caseID) {
var approverSet = false;
var caseGR = new GlideRecord('sn_hr_core_case');
if (caseGR.get(caseID)) {
var approvalWorkFlowContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGR);
if (approvalWorkFlowContext.scratchpad.approvers.length > 0)
approverSet = true;
}
return approverSet;
};
/*
* Adds approvers to the case and updates case worflow
*
* @param
* approvers: comma separated string value containing sys_user ids
* table: string value of table name
* caseID: HR case sys_id string value
*
* @returns error message as
* object {
* error: string error message if invalid user or missing caseID
* }
* OR null for success
*/
hr_ApprovalUtil.addApproversToCase = function(approvers, table, caseID) {
var response = {};
if (table && caseID) {
//add approvers to case
var failedToAddApprovers = [];
//when 'some' approvers are missing, list can be empty.
if (approvers) {
var approversList = approvers.split(',');
var hrSubstituteApproverGR = new GlideRecord('sn_hr_core_substitute_approver');
for (var i = 0; i < approversList.length; i++) {
hrSubstituteApproverGR.initialize();
hrSubstituteApproverGR.approver = approversList[i];
hrSubstituteApproverGR.hr_case = caseID;
var inserted = hrSubstituteApproverGR.insert();
if (!inserted)
failedToAddApprovers.push(approversList[i]);
}
hr_ApprovalUtil.setApprovalTriggerForMissingApprover(caseID);
}
//update case workflow context
var caseGR = new GlideRecord(table);
if ( caseGR.get(caseID) ) {
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGR);
if (approvalContext)
new global.Workflow().broadcastEvent(approvalContext.sys_id, 'sn_hr_core.substitute_approvers');
}
//error message for either failed insertion or no workflow found
if ( (failedToAddApprovers.length > 0) || !approvalContext) {
response = {
error: failedToAddApprovers.length > 0 ? gs.getMessage('Insertion of following approval records failed {0}', failedToAddApprovers.toString()) : '' +
approvalContext ? '' : gs.getMessage('No workflow found for case {0}', caseID)
};
}
} else {
response = {
error: table ? gs.getMessage('Table name is not set.') : '' +
caseID ? gs.getMessage('HR case sys_id is not set.') : ''
};
}
return JSON.stringify(response);
};
/*
*
*
* @param
* caseGr: HR case gliderecord
* vars: variable to pass to workflow
* vars = {};
vars.adhoc_approvers: comma seperated sys_id(s) of approver users
vars.wait_for : wait for option ['anyone','everyone','first_response']
vars.on_rejection :reject option ['resubmit','close_case']
*
*
*/
hr_ApprovalUtil.startAdhocApprovalFlow = function(caseGr,vars) {
var w = new global.Workflow();
w.startFlow(hr_ApprovalUtil.WORKFLOW_ID, caseGr,"",vars);
};
/*
* Returns boolean true if adhoc approval action can be performed
*
* @param
* caseGr: HR case gliderecord
*
* @returns
* boolean true if adhoc approval action can be performed false otherwise
*/
hr_ApprovalUtil.isAdhocApprovers = function(caseGr) {
if(!hr_ApprovalUtil.checkApproverCaseOption(caseGr))
return false;
if (!new hr_Delegation().isAssignedOrDelegated(caseGr))
return false;
var approvalContext = hr_ApprovalUtil.getApprovalSubflowsForCase(caseGr);
var result = (approvalContext == null) && (caseGr.state == '10' || caseGr.state == '18') ;
return result;
};
/*
* Returns boolean true if adhoc approval action can be performed
*
* @param
* caseGr: HR case gliderecord
*
* @returns
* boolean true if AgentCanAddApprover case option is added
* in HR service false otherwise
*/
hr_ApprovalUtil.checkApproverCaseOption = function(caseGr) {
var caseOptions = caseGr.hr_service.case_options;
var optionsGr = new GlideRecord('sn_hr_core_service_option');
optionsGr.get('value', 'AgentCanAddAnApproval');
if (!gs.nil(caseOptions) && caseOptions.indexOf(String(optionsGr.sys_id)) > -1)
return true;
return false;
};
/*
* Set Approval triggered value for missing approver records
*
* @param
* caseId: HR case sys Id
* triggerValue: true/false
*
*/
hr_ApprovalUtil.setApprovalTriggerForMissingApprover = function(caseId) {
var substituteApproverGR = new GlideRecord('sn_hr_core_substitute_approver');
substituteApproverGR.addNotNullQuery('missing_approver');
substituteApproverGR.addQuery('hr_case', caseId);
substituteApproverGR.addQuery('approval_triggered', false);
substituteApproverGR.query();
substituteApproverGR.setValue('approval_triggered', true);
substituteApproverGR.updateMultiple();
};
Sys ID
3f09e559536232003585c3c606dc34d6