Name

sn_hr_core.hr_Utils

Description

Generic functionality for the HR application

Script

var hr_Utils = Class.create();

hr_Utils.prototype = {
  initialize : function() {
  	this.HR_CORE = 'sn_hr_core';
  	this.HR_SP = 'sn_hr_sp';
  	this.HR_LE = 'sn_hr_le';
  	this.HR_INTEGRATIONS = 'sn_hr_integrations';
  	this.DEFAULT_JOB_FIELDS = 'employment_type,position,position_code,office_number,location_type,offboard_type,employment_start_date,employment_end_date,notice_period,probation_period,probation_end_date,location,work_phone,work_email,manager,department';
  	this.JOB_DATES_MAP = {
  		'employment_start_date' : 'job_start_date',
  		'employment_end_date' : 'job_end_date'
  	};
  },
  
  /*
  * Get list count for query
  * @param
  *  queries: array list of string containing table and encoded query separated by single space
  *  example: ['table_name encoded_query']
  *
  * @retuns
  *  object containing record count for query
  *  example: {'query string as passed in param': integer count}
  */
  getListCount: function(queries) {
  	var queryCounts = {};
  	
  	for (var i=0; i<queries.length; i++) {
  		
  		var query = queries[i];
  		var queryParms = query.split(' ');
  		var table = queryParms[0];
  		var encodedQuery = queryParms[1];
  		var count = 0;
  		
  		//get row count for encoded query
  		var gr = new GlideAggregate(table);
  		gr.addAggregate('COUNT');
  		gr.addEncodedQuery(encodedQuery);
  		gr.query();
  		if (gr.next())
  			count = gr.getAggregate('COUNT');
  		
  		//add resulting count for query
  		queryCounts[query] = count;
  	}
  	
  	return queryCounts;
  },

  userHasSPClientRole : function(user){
  	var userId = user || gs.getUserID();
  	var gr = new GlideRecord('sys_user_has_role');
  	gr.addQuery('user', userId);
  	gr.addQuery('role.name','LIKE','sn_hr_sp.hrsp_%');
  	gr.setLimit(1);
  	gr.query();
  	return gr.hasNext();
  },

  userHasHRRole : function(user) {
  	if(gs.nil(user))
  		return gs.hasRole(hr.ROLE_HR_CASE_READER);
  	
  	var gr = new GlideRecord('sys_user_has_role');
  	gr.addQuery('user', user);
  	gr.addQuery('role.name', hr.ROLE_HR_CASE_READER);
  	gr.setLimit(1);
  	gr.query();
  	return gr.hasNext();
  },

  // Used as a reference qualifier in Disciplinary issue RP variable
  getHRClientUsers: function() {
  	return "active=true";
  },

  //Used as a reference qualifier in Opened For field of Case form
  getOpenedForUsers: function() {
  	if (this.checkUserHasRole(hr.ROLE_HR_CASE_WRITER))
  		//return all client users if case_writer
  		return this.getHRClientUsers();
  	else {
  		var users = [gs.getUserID()];
  		return 'sys_idIN'+ users.join(',');
      }
  },

  //Used as a reference qualifier in Subject Person field of Case form
  getSubjectPersonUsers: function() {
  	if (this.checkUserHasRole(hr.ROLE_HR_CASE_WRITER))
  		//return all client users if case_writer
  		return this.getHRClientUsers();
  	else{
          //return only the subordinates and himself for current user
          var users = this.getHRClientSubordinateUsers(gs.getUserID());
          return 'sys_idIN'+ users.join(',');
      }
  },

  getHRClientSubordinateUsers:function(sysid){
  	var subusers = new sn_hr_core.hr_SysUser().getAllReports(sysid).split(',');
  	subusers.push(sysid);
  	return subusers;
  },

  getHRRoles:function(searchString){
  	var ids = [];
  	var gr = new GlideRecord('sys_user_role');
  	gr.addQuery('name','LIKE',searchString);
  	gr.query();
  	while (gr.next())
  		ids.push(gr.sys_id.toString());

  	return ids;
  },
  
  getCOEFromTopicDetails: function(topicDetailsId) {
  	var detailGr = new GlideRecord("sn_hr_core_topic_detail");
  	if (detailGr.get(topicDetailsId) && !gs.nil(detailGr.topic_category.coe))
  		return detailGr.topic_category.coe.toString();
  	return "";
  },

  canUpdateContact: function(){
  	var gr = new GlideRecord(hr.TABLE_BENEFICIARY);
  	if (gr.get('contact.user', previous.user)) {
  		//Beneficiary found but user is same returning true
  		if (current.user == previous.user)
  			return true;
  		else
  			//Beneficiary found and user is not same returning false
  			return false;
  	} else
  		//Beneficiary not found returning true
  		return true;
  },

  hasVIPUser: function(){
  	var gr = new GlideRecord('sys_user');
  	var q = gr.addQuery('sys_id', previous.opened_for);
  	q.addOrCondition('sys_id', previous.subject_person);
  	gr.addQuery('vip', true);
  	gr.setLimit(1);
  	gr.query();
  	return gr.hasNext();
  },

  /*
   * getRoledUsers method is getting deprecated as there is no call to this method
   */
  getRoledUsers: function(queryCondition, roleListIds) {
  	var users = {};
  	var gr = new GlideRecord('sys_user_has_role');
  	if (roleListIds) {
  		gr.addQuery('role', queryCondition, roleListIds);
  	}
  	gr.query();
  	while (gr.next()) {
  		users[gr.user.toString()] = true;
  	}

  	var ids = [];
  	for (var id in users)
  		ids.push(id);

  	return ids;
  },

  getAvailableTemplates : function() {
  	var sysIds = '';
  	return sysIds;
  },

  userHasRole : function(user) {
  	var gr = new GlideRecord('sys_user_has_role');
  	gr.addQuery('user',user);
  	var qc = gr.addQuery('role.name','sn_hr_sp.hrsp_employee');
  	qc.addOrCondition('role.name','sn_hr_sp.hrsp_new_hire');
  	gr.setLimit(1);
  	gr.query();
  	return gr.hasNext();
  },
  
  checkUserHasRole: function(role_name){
  	var val = gs.getProperty("sn_hr_core.include_elevated_roles", "false");
  	var isRolePresent = false;
  	if(val == 'true')
  		isRolePresent =  gs.hasRole(role_name); 
  	else{
  		var roles = gs.getUser().getRoles();
  		isRolePresent = roles.indexOf(role_name) > -1;
  	}
  	return isRolePresent;
  },
  
  getRolesOfUser: function(userId) {
  	var val = gs.getProperty("sn_hr_core.include_elevated_roles", "false");
  	if(val == 'true')
  		return this._getAllActiveRolesOfUser(userId);
  	else
  		return gs.getUser().getRoles();
  },
  
  _getAllActiveRolesOfUser: function(userId) {
  	var rolesList = [];
  	var grHasRole = new GlideRecord('sys_user_has_role');
  	grHasRole.addQuery('state', 'active');
  	grHasRole.addQuery('user', userId);
  	grHasRole.query();
  	
  	while(grHasRole.next()) 
  		rolesList.push(grHasRole.role.name + '');
  	return rolesList;
  },

  /*
  * Convenience method to prevent the code becoming unreadable from the useful debug statements
  */
  _logDebug : function(str) {
  	if (gs.isDebugging())
  		gs.debug(str);
  },

  /**
  * GlideRecordSecure does not present an issue here as we are not actually reading the record - just checking for hasNext.
  * @param hrcase GlideRecord A glide record representing the HR Case.
  * @return boolean True if there is a 'requested' approval record for the given case.
  */
  hasApprovalPending : function(hrcase) {
  	var gr = new GlideRecordSecure('sysapproval_approver');
  	gr.addActiveQuery();
  	gr.addQuery('sysapproval', hrcase.sys_id);
  	gr.addQuery('state', 'requested');
  	gr.setLimit(1);
  	gr.query();

  	return gr.hasNext();
  },

  canAccessManagedDoc: function(current) {
  	var docRevGR = new GlideRecord('dms_document_revision');
  	docRevGR.addActiveQuery();
  	docRevGR.addQuery('stage', 'published');
  	docRevGR.query();

  	var docRevs = [];
  	while (docRevGR.next()) {
  		if (this._isDocRevOwner(docRevGR))
  			docRevs.push(docRevGR.getUniqueValue());
  	}
  	return docRevs;
  },

  _isDocRevOwner: function(docRevGR) {
  	return (docRevGR.document.owner == gs.getUserID()) || gs.getUser().isMemberOf(docRevGR.document.owning_group.toString());
  },

  isWhiteListed : function(field, userId) {
  	if (this.checkUserHasRole(hr.ROLE_HR_PROFILE_WRITER))
  		return true;
  	// Check if the current field is present in the whitelist
  	var editables = hr.DEFAULT_WHITELIST;

  	var gr = new GlideRecord('sys_properties');
  	if (gr.get('name', 'sn_hr_core.hr_profile_editable_fields'))
  		editables = gr.value + ',';

  	return !gs.nil(userId) && userId == gs.getUserID()
  		&& this._arrayContains(editables.split(','), field);
  },

  _arrayContains : function(ary, seed) {
  	for (var i = 0; i < ary.length; i++)
  		if (ary[i].trim() === seed)
  			return true;
  	return false;
  },

  getRelevantPDFTemplates : function(record) {
  	var strReturn = "sys_idIN";
  	strReturn += this.getPDFTemplateBasedOnDocumentType(record.document_type, record.subject_person);

  	return strReturn;
  },


  /*
  	This method returns comma separated sys_ids of PDF Templates 
  	matching document type and user's HR criteria
  	
  	@param documentType: Document Type to filter PDF Templates
  	@param subjectPerson: Subject person whose HR criteria will be 
  	checked against the HR Criteria of PDF Templates
  	
  	@return Comma separated string of PDF Template sys_ids
  */
  getPDFTemplateBasedOnDocumentType : function(documentType, subjectPerson){

  	var documentTemplates = new GlideRecord('sn_hr_core_document_template');
  	documentTemplates.addActiveQuery();

  	if (documentType)
  		documentTemplates.addQuery('document_type', documentType);

  	documentTemplates.query();

  	var validTemplates = [];

      while (documentTemplates.next()) {
          if (this._criteriaHelper(documentTemplates, subjectPerson)){
  			if (gs.getUserID() == 'system' || documentTemplates.canRead()) 
  				validTemplates.push(documentTemplates.getUniqueValue());
  		}
      }

  	return validTemplates.join(',');
  },

  /*
  	This method returns an array of objects containing sys_id and 
  	display value of PDF Templates matching document type and 
  	user's HR criteria
  	
  	@param documentType: Document Type to filter PDF Templates
  	@param subjectPerson: Subject person whose HR criteria will be 
  	checked against the HR Criteria of PDF Templates
  	
  	@return array of objects containing sys_id and display value of PDF Templates
  */
  getPDFTemplateObjectsForDocumentType : function(documentType, subjectPerson){

  	var documentTemplates = new GlideRecord('sn_hr_core_document_template');
  	documentTemplates.addActiveQuery();

  	if (documentType)
  		documentTemplates.addQuery('document_type', documentType);

  	documentTemplates.query();
  	var validTemplates = [];

      while (documentTemplates.next()) {
  		if (this._criteriaHelper(documentTemplates, subjectPerson)) {
  			if (gs.getUserID() == 'system' || documentTemplates.canRead()) {
  				var templateInfo = {};
  				templateInfo["sys_id"] = documentTemplates.getUniqueValue();
  				templateInfo["display_value"] = documentTemplates.getDisplayValue();
  				validTemplates.push(templateInfo);
  			}
  		}
       }
  	return validTemplates;
  },
  _criteriaHelper:function(template, subject_person) {

  	if (template && subject_person) {
  		var hrCriteria = template.getValue('hr_criteria');

  		if (hrCriteria) {
  			var isValidCriteria = new hr_Criteria().evaluateById(hrCriteria+'', subject_person +'');

  			if (isValidCriteria) {
  				//If HR criteria is valid return document template
  				return template;
  			}
  		} else {
  			//If no HR Criteria, return document template
  			return template;
  		}
  	}

  	return "";
  },

  /*
   * Convert the parameters filled into a Record Producer, into a GlideRecord.  Map and fields using an
   * optional map object.
   */
  fillInFromMap : function(gr, parameters, map) {
  	// Fill in the new Profile records
  	for ( var key in parameters) {
  		var field = (map && map[key]) ? map[key] : key;

  		if (gr.isValidField(field))
  			gr.setValue(field, parameters[key]);
  	}
  },

  /*
   * Convert the fields filled into a GlideRecord, into a Record Producer.
   * Map and fields using an map object that is also inverted from RP -> GR map.
   */
  translateFieldFromMap : function(source, fieldMap, labelMap) {
  	var dest = {};
  	var fields = this.invertMap(fieldMap);

  	// Fill in the new Profile records
  	for ( var key in source) {
  		var destKey = (fields && fields[key]) ? fields[key] : key;
  		dest[destKey] = (labelMap && labelMap[destKey]) ? labelMap[destKey] : source[destKey];
  	}

  	return dest;
  },

  /*
   * Invert a map so that the key and value are swapped; not generalizable as this only
   * works for map[String] = String;
   */
  invertMap : function(inverseMap) {
  	var map = {};
  	for ( var key in inverseMap) {
  		var label = inverseMap[key];
  		map[label] = key;
  	}

  	return map;
  },

  getFieldsFromTable : function(table, whitelist, blacklist) {
  	var fieldsData = {};
  	var badPrefix = "sys_";

  	// Load the records from the passed in table directly
  	var grTable = new GlideRecord(table);
  	var elements = grTable.getElements();
  	var schemas = [];
  	for (var x = 0; x < elements.length; x++) {
  		var ed = elements[x].getED();
  		schemas.push(ed);
  	}
  	for (var i = 0; i < schemas.length; i++) {
  		var glideElement = schemas[i];
  		if ((glideElement.getName() + '').indexOf(badPrefix) !== 0)
  			if (this._useField(glideElement, whitelist, blacklist))
  				fieldsData[glideElement.getName()] = glideElement.getLabel();
  	}

  	return fieldsData;
  },

  _useField : function(ge, whitelist, blacklist) {
  	if (whitelist && whitelist[ge.getName()] === undefined)
  		return false;

  	if (blacklist && blacklist[ge.getName()] !== undefined)
  		return false;

  	return true;
  },

  dereferenceField : function(ref, table, column) {
  	var gr = new GlideRecord(table);
  	if (gr.get(ref))
  		return gr.getValue(column);
  },

  /* Start of Deprecated functions as of Helsinki */

  /*
   * Update a sn_hr_core_case record total_percent_complete field when related tasks are completed
   */
  updateHRCasePercentComplete : function(gr) {
  	return new hr_Case().updateHRCasePercentComplete(gr);
  },

  generateUserName : function(first_name, last_name) {
  	return new hr_SysUser().generateUserName(first_name, last_name);
  },

  createProfileFromUser : function(userId) {
  	return new hr_Profile().createProfileFromUser(userId);
  },

  /*
  * Synchronize data between the sys_user and the sn_hr_core_profile table
  * @param gr - GlideRecord - The record to synchronize changes from
  */
  syncProfileWithUser : function(_gr) {
  	new sn_hr_core.hr_Synchronize().syncRecord(gr);
  },

  /* 
   * Synchronize data between the sys_user and the sn_hr_core_profile table
   * @param gr - GlideRecord - The record to synchronize changes from
   */
  syncProfileFields : function(gr) {
  	new sn_hr_core.hr_Synchronize().syncRecord(gr);
  },
  
  /*
   * Synchronises Primary job data between sn_hr_core_job (Job) table and the sn_hr_core_profile (HR Profile) table 
   * @param
   *    _gr - GlideRecord of sn_hr_core_job table
   *    copyAllFields - "true"/"false" to copy only changed field or all fields
   *	  resetEmpDates - true/false to reset employment dates in HR Profile 
   */
  syncJobFields : function(_gr, copyAllFields, resetEmpDates) {
  	var tblName = _gr.getTableName();
  	var destGr;
  	var excludeFields = ['correlation_id','source']; //HR Integration fields
  	// Exit if not sn_hr_core_job or sn_hr_core_profile
  	if (tblName != hr.TABLE_JOB && tblName != hr.TABLE_PROFILE)
  		return null;

  	// Synch only Primary job data to HR Profile table
  	if (tblName == hr.TABLE_JOB && _gr.getValue("primary")) {
  		var map = resetEmpDates? this.JOB_DATES_MAP : {};
  		destGr = new GlideRecord(hr.TABLE_PROFILE);
  		if (destGr.get(_gr.getValue("hr_profile"))) {
  			destGr.setValue('primary_job', _gr.getUniqueValue());
  			return this.syncProfilesWithMap(_gr, destGr, map, excludeFields, copyAllFields); 
  		}
  	}
  	
  	if (tblName == hr.TABLE_PROFILE) {
  		destGr = this.getPrimaryJobRecord(_gr.getValue('user'));
  		if (!gs.nil(destGr)) 
  			return this.syncProfilesWithMap(_gr, destGr, {}, excludeFields, copyAllFields);
  	}
  	return null;
  },

  // Sync fields between GlideRecord objects with field map
  syncProfilesWithMap : function(srcGr, destGr, map, exclusionList, copyAllFields) {
  	var srcFields = this._getChangedFields(srcGr, copyAllFields);
  	var touched = false;
  	var destFields = destGr.getElements();
  	for (var x = 0; x < destFields.length; x++) {
  		var element = destFields[x];
  		var elName = element.getName();

  		var isExcluded = false;
  		for ( var exclude in exclusionList)
  			if (elName == exclusionList[exclude])
  				isExcluded = true;

  		if (elName in srcFields && (!isExcluded)) {
  			destGr.setValue(elName, srcGr.getValue(elName)== null ?  "" : srcGr.getValue(elName));
  			touched = true;
  		}
  	}
  	for ( var key in map) {
  		if (map[key] in srcFields) {
  			var keyVal= srcGr.getValue(map[key])== null ?  "" : srcGr.getValue(map[key]);
  			destGr.setValue(key, keyVal);
  			touched = true;
  		}
  	}
  	if (touched) {
  		destGr.getUniqueValue();
  		destGr.update();
  	}
  	return destGr;
  },


  updateUserMismatchField : function(srcField, srcGr, destGr, copyAllFields) {
  	var srcValue = srcGr.getValue(srcField);
  	if (srcValue) {
  		var touched = false;
  		var srcFieldChanges = this._getChangedFields(srcGr);
  		if (srcField == "title" && (srcField in srcFieldChanges || copyAllFields == 'true')) {
  			var position = new GlideRecord("sn_hr_core_position");
  			if (position.get("position", srcGr.title)) {
  				destGr.setValue('position', position.sys_id);
  				touched = true;
  			} else
  				gs.warn("[hr_Utils] User title '" + srcGr.title + "' does not exist in sn_hr_core_position");
  		}
  		if (srcField == "country" && (srcField in srcFieldChanges || copyAllFields == 'true')) {
  			var country = new GlideRecord("core_country");
  			country.get("iso3166_2", srcGr.country); // iso3166_2 is column name for country code in country table.
  			destGr.setValue("country", country.sys_id);
  			touched = true;
  		}
  		if (touched) {
  			destGr.setWorkflow(false);
  			destGr.getUniqueValue();
  			destGr.update();
  		}
  	}
  },
  
  /*
  * Create a job record in sn_hr_core_job table for the user
  * @param
  *    srcGr - source glide record, i.e sn_hr_core_profile
  * @return
  *    primary job sys_id or null
  */
  createPrimaryJobFromProfile: function(srcGr) {
  	var retJobId = '';
  	var userId = srcGr.getValue('user');
  	var jobFields = gs.getProperty('sn_hr_core.hr_profile_job_fields', this.DEFAULT_JOB_FIELDS).split(',');
  	
  	var destGr = new GlideRecord(hr.TABLE_JOB);
  	destGr.initialize();
  	destGr.setValue('primary', true);
  	destGr.setValue('hr_profile', srcGr.getValue('sys_id'));
  	destGr.setValue('user', userId);
  	
  	for (var i = 0; i < jobFields.length; i++) {
  		var elName = jobFields[i];
  		if(elName == 'manager' || elName == 'department' || elName == 'location') //Primary Job related fields in User record
  			destGr.setValue(elName, srcGr.user[elName]);
  		else
  			destGr.setValue(elName, srcGr.getValue(elName));
  	}
  	destGr.setValue('job_start_date', srcGr.getValue('employment_start_date'));
  	destGr.setValue('job_end_date', srcGr.getValue('employment_end_date'));
  	retJobId = destGr.insert();
  	
  	if(gs.nil(retJobId))
  		retJobId = this.getPrimaryJob(userId);
  	return retJobId;
  },
  
  
  /*
  * Create a job record in sn_hr_core_job table for the user
  * @params
  *    profileGr - HR Profile glide record, i.e sn_hr_core_profile
  *    parameters - questions from Record producer
  *    isPrimary - boolean, create primary or non-primary job
  * @return
  *    new job sys_id or null
  */
  createJobFromParameters: function(profileGr, parameters, isPrimary) {
  	var hrProfileId = profileGr.getUniqueValue();
  	var userId = profileGr.getValue('user');
  	
  	//Set parameters for fields like hr_profile, user, primary in Jobs tables
  	parameters['hr_profile'] = hrProfileId;
  	parameters['user'] = userId;
  	parameters['primary'] = (gs.nil(this.getPrimaryJob(userId)) || isPrimary)? true : false;
  	
  	var grJob = new GlideRecord('sn_hr_core_job');
  	grJob.initialize();
  	
  	this.fillInFromMap(grJob, parameters, this.JOB_DATES_MAP);
  	
  	return grJob.insert();
  },
  	
  /*
  * Get the primary job from sn_hr_core_job table for the user
  * @param
  *    userId - user sys_id 
  * @return
  *    primary job sys_id or null
  */
  getPrimaryJob: function(userId) {
  	if(!userId)
  		return null;
  	var primaryJobGr = this.getPrimaryJobRecord(userId);
  	
  	return !gs.nil(primaryJobGr)? primaryJobGr.getUniqueValue() : null;
  },
  
  /*
  * Switch the primary job of the user 
  * @params
  *    userId - User sys_id from sys_user
  *    jobId - Job sys_id from sn_hr_core_job
  * @return
  *    encoded json with status and message
  */
  switchPrimaryJob: function(userId, jobId) {
  	//Validations
  	if(gs.nil(userId)) {
  		this._logDebug('[hr_Utils] switchPrimaryJob: User input is null');
  		return this._getStatusMsg('error', gs.getMessage('User input to switch primary job is null'));
  	}
  	if(gs.nil(jobId)) {
  		this._logDebug('[hr_Utils] switchPrimaryJob: Job input is null');
  		return this._getStatusMsg('error', gs.getMessage('Job input to switch primary job is null'));
  	}
  	
  	//Gets the current primary job and set the primary flag to false
  	var currentPrimaryJob = this.getPrimaryJob(userId);
  	if(!gs.nil(currentPrimaryJob)) {
  		var isPrimaryJobDisabled = this.setPrimaryFieldForJob(currentPrimaryJob, false);
  		if(!isPrimaryJobDisabled)
  			return this._getStatusMsg('error', gs.getMessage("Disabling existing primary job of the user failed"));
  	}
  	
  	//Set the primary flag to true for the job in the parameter
  	var isPrimaryJobSwitched = this.setPrimaryFieldForJob(jobId, true);
  	if(isPrimaryJobSwitched)
  		return this._getStatusMsg('success', gs.getMessage("Switched primary job for the user successfully"));
  	else {
  		this.setPrimaryFieldForJob(currentPrimaryJob, true); //Fallback to prior primary job, as switching primary job failed
  		return this._getStatusMsg('error', gs.getMessage("Switching primary job for the user failed"));
  	}
  },
  
  /*
  * Enables/Disables a job as primary for the user in sn_hr_core_job table
  * @param
  *    jobId - job id of the user
  *	 isPrimary - true/false
  * @return
  *    boolean - On successful update, return true else false
  */
  setPrimaryFieldForJob: function(jobId, isPrimary) {
  	if(!jobId)
  		return false;
  	var grJob = new GlideRecord('sn_hr_core_job');
  	
  	if(grJob.get(jobId)) {
  		grJob.setValue('primary', isPrimary);
  		return gs.nil(grJob.update())? false: true;
  	}
  	this._logDebug('[hr_CaseUtils] setPrimaryFieldForJob: The job with sys_id: ' + jobId + ' is not in the Jobs table');
  	return false;
  },
  
  /*
  * Get the primary job GlideRecord from sn_hr_core_job table for the user
  * @param
  *    userId - user sys_id 
  * @return
  *    primary job GlideRecord or null
  */
  getPrimaryJobRecord: function(userId) {
  	if(!userId)
  		return null;
  	var grJob = new GlideRecord('sn_hr_core_job');
  	grJob.addQuery('primary', true);
  	grJob.addQuery('user', userId);
  	grJob.setLimit(1);
  	var grJobOR = grJob.addNullQuery('job_end_date');
  	grJobOR.addOrCondition('job_end_date', '>=', 'javascript:gs.beginningOfToday()');
  	grJob.addNotNullQuery('job_start_date');
  	grJob.orderBy('job_start_date');
  	grJob.query();
  	
  	if(grJob.next())
  		return grJob;
  	
  	this._logDebug('[hr_CaseUtils] getPrimaryJobRecord: The user with sys_id: ' + userId + ' does not have a primary job record in Job table');
  	return null;
  },

  _updateProfileMismatchField : function(srcField, srcGr, destGr) {
  	var srcValue = srcGr.getValue(srcField);
  	if (srcValue) {
  		var touched = false;
  		var srcFieldChanges = this._getChangedFields(srcGr);
  		if (srcField == "position" && srcField in srcFieldChanges) {
  			var destTitleValue = new GlideRecord("sn_hr_core_position");
  			if (destTitleValue.get(srcValue)) {
  				destGr.setValue("title", destTitleValue.getDisplayValue());
  				touched = true;
  			}
  		}
  		if (srcField == "country" && srcField in srcFieldChanges) {
  			var destValue = new GlideRecord("core_country");
  			if (destValue.get(srcValue)) {
  				destGr.setValue("country", destValue.iso3166_2); // iso3166_2 is column name for country code in country table.
  				touched = true;
  			}
  		}
  		if (touched) {
  			destGr.getUniqueValue();
  			destGr.update();
  		}
  	}
  },

  /*
   * Return an array containing elements of a GlideRecord that
   * have changed. Do not return calculated fields
   */
  _getChangedFields : function(srcGr, copyAllFields) {
  	var changed = {};
  	var fields = srcGr.getElements();
  	for (var x = 0; x < fields.length; x++) {
  		var element = fields[x];
  		if (copyAllFields == 'true' || element.changes()) {
  			var elName = element.getName();
  			if (!element.getED().isVirtual() && !elName.startsWith('sys_'))
  				changed[elName] = element;
  		}
  	}
  	return changed;
  },

  maskSSN : function(str) {
  	if (gs.nil(str))
  		return "";
  	//Remove the unwanted special characters
  	str = this.sanitize(str);
  	var trailingCharsIntactCount = 4;
  	str = str.toString();
  	var newstr = str;

  	if (str.length > 4) {
  		newstr = str.substring(0, str.length - trailingCharsIntactCount);
  		newstr = newstr.replace(/./g, 'x') + str.slice(-trailingCharsIntactCount);

  	}
  	return newstr;
  },

  /**
   * Remove the unwanted speacial characters from the String
   * Characters inside regex array will be removed from string.
   */
  sanitize : function(str){
  	var cleanStr = str.replace(/[-()]/g,'');
  	return cleanStr;
  },

  getDocRevisionInfoByDocumentId : function(docId) {
  	var docRevision = null;

  	var gr = new GlideRecord("dms_document_revision");
  	gr.addQuery("document", docId);
  	gr.addQuery("stage", "published");
  	gr.query();
  	if (gr.next()  && gr.canRead()) {
  		docRevision = {};
  		var info = this.getAttachmentInfo("dms_document_revision", gr.getUniqueValue());
  		
  		docRevision.filename = this.getDocumentNameById(docId);
  		docRevision.href = "/sys_attachment.do?sys_id=" + info.sys_id;
  		docRevision.contentType = info.content_type;
  		docRevision.bytes = info.size_bytes;
  	}
  	return docRevision;
  },

  getDocumentNameById : function(docId) {
  	var gr = new GlideRecord("dms_document");
  	if (gr.get(docId))
  		return gr.getValue("name");
  },

  getAttachmentInfo : function(tableName, tableSysId) {
  	var gr = new GlideRecord("sys_attachment");
  	gr.addQuery("table_name", tableName);
  	gr.addQuery("table_sys_id", tableSysId);
  	gr.setLimit(1);
  	gr.query();
  	var info = {};
  	if (gr.next()) {
  		info.sys_id = gr.getUniqueValue();
  		info.size_bytes = gr.getValue("size_bytes");
  		info.content_type = gr.getValue("content_type");
  	}
  	return info;
  },

  /**
  								* Get the (actual) duration, between startTime and endTime
  								*/
  calcDuration : function(/* GlideDateTime or String */startTime, /* GlideDateTime or String */endTime) {
  	if (!startTime || !endTime)
  		return 0;

  	endTime = new GlideDateTime(endTime);
  	startTime = new GlideDateTime(startTime);
  	var offsetEndTime = endTime.getTZOffset();
  	var offsetStartTime = startTime.getTZOffset();
  	return Math.floor((endTime.getNumericValue() + offsetEndTime) / 1000) - Math.floor((startTime.getNumericValue() + offsetStartTime) / 1000);
  },

  /**
  * Determine if a user can read HR Tables by checking if they have any HR roles
  * @return boolean - Whether a user can read any HR Tables
  */
  canReadHRTables : function() {
  	if (gs.getProperty('sn_hr_core.include_elevated_roles', 'false') == 'true') {
  		var grHasRole = new GlideRecord('sys_user_has_role');
  		grHasRole.addQuery('state', 'active');
  		grHasRole.addQuery('user', gs.getUserID());
  		grHasRole.addQuery('role.name', 'STARTSWITH', hr.ROLE_HR_ANY);
  		grHasRole.setLimit(1);
  		grHasRole.query();
  		return grHasRole.hasNext();
  		
  	} else {
  		var roles = gs.getUser().getRoles();
  		for (var i = 0;i < roles.length; i++)
  			if (roles[i].indexOf(hr.ROLE_HR_ANY) == 0)
  				return true;
  		return false;
  	}
  },

  addUserRole: function(role, userSysId) {
  	if(this.isHRRole(role)){
  		var gr = new GlideRecord('sys_user_has_role');
  		gr.initialize();
  		gr.user = userSysId;
  		gr.role = role;
  		var res = gr.insert();
  		if(!res)
  			gs.addErrorMessage(gs.getMessage("Your role does not allow assignment of {0} role", this._getRoleName(role)));
  	}
  },

  isHRRole: function(role){
  	var gr = new GlideRecord('sys_user_role');
  	gr.addQuery('sys_id', role);
  	gr.addQuery('name', 'STARTSWITH', 'sn_hr_');
  	gr.setLimit(1);
  	gr.query();
  	return gr.hasNext();
  },

  // Removes all core roles and portal roles.
  removeRolesAssigned:function(userSysId){
  	var answer = [];
  	var gr = new GlideRecord('sys_user_role');
  	var gc = gr.addQuery('name', 'STARTSWITH', "sn_hr_core.hrsm");
  	gc.addOrCondition('name', 'STARTSWITH', "sn_hr_sp.hrsp");
  	gr.query();
  	while (gr.next()) {
  		answer.push(gr.getValue('name'));
  	}
  	if(answer.length > 0){
  		new global.HRSecurityUtilsAjax().removeUserRoles(userSysId, answer.join(','));
  	}
  },

  // Assigns roles based on condition mentioned in HR condition table
  matchingPortalRoles:function(current){
  	var userSysId = current.user.sys_id;
  	var conditions = this._matchingPortalRolesCondition('sn_hr_core_client_role_rule');
  	for (var i = 0; i < conditions.length; i++) {
  		var bool = GlideFilter.checkRecord(current, conditions[i].conditions);
  		if (bool) {
  			var hasRole = this._checkIsRolePresent(userSysId, conditions[i].roleName);
  			if(hasRole){
  				this.addUserRole(conditions[i].roleName, userSysId);
  			}
  		}
  	}
  },

  // Checks whether user already has role. If he has core role it will remove and assign portal role if service portal is enabled.
  _checkIsRolePresent:function(userSysId,role){
  	var hasRole = new GlideRecord('sys_user_has_role');
  	var roleName = this._getRoleName(role);
  	if(roleName.indexOf("hrsm") > -1){
  		roleName = roleName.replace("core.hrsm","sp.hrsp");
  		hasRole.addQuery('user.sys_id',userSysId);
  		hasRole.addQuery('role.name',roleName);
  		hasRole.query();
  		while(hasRole.next()){
  			return false;
  		}
  		return true;
  	}
  	if(roleName.indexOf("hrsp") > -1){
  		roleName = roleName.replace("sp.hrsp","core.hrsm");
  		hasRole.addQuery('user.sys_id',userSysId);
  		hasRole.addQuery('role.name',roleName);
  		hasRole.query();
  		while(hasRole.next()){
  			new global.HRSecurityUtilsAjax().removeUserRoles(userSysId,role);
  		}
  		return true;
  	}
  	return false;
  },

  //   Gets role name from role sys_id.
  _getRoleName:function(role){
  	var roleName = new GlideRecord('sys_user_role');
  	roleName.addQuery('sys_id',role);
  	roleName.setLimit(1);
  	roleName.query();
  	if(roleName.next()){
  		return roleName.name;
  	}
  },

  _matchingPortalRolesCondition:function(table) {
  	var criteria = new GlideRecord(table);
  	var conditions = [];
  	criteria.addQuery('active', 'true');
  	criteria.query();
  	while (criteria.next()) {
  		var condition = criteria.condition.condition.toString();
  		var role = criteria.role.toString();
  		conditions.push({conditions: condition,roleName: role});
  	}
  	return conditions;
  },

  //   Assigns new role based on new condition.
  assignRolesPerCondition:function(condition,role){
  	var user = new GlideRecord('sn_hr_core_profile');
  	user.addEncodedQuery(condition);
  	user.query();
  	while(user.next()){
  		var bool = this._checkIsRolePresent(user.user.sys_id,role);
  		if(bool){
  			this.addUserRole(role,user.user.sys_id);
  		}
  	}
  },

  //   Removes previously assigned roles based on previous condition.
  removePreviouslyAssignedRoles:function(condition,roleName){
  	var user = new GlideRecord('sn_hr_core_profile');
  	user.addEncodedQuery(condition);
  	user.query();
  	while(user.next()){
  		new global.HRSecurityUtilsAjax().removeUserRoles(user.user.sys_id,roleName);
  	}
  },

  /* Get list of active cases the user has been requested to approve
   * @param userId String sys_id of user
   * @return String csv of case sys_id's the user has an approval for
   */
  getCaseSysIdListForApprovals: function(userId) {
  	var caseSysIdList = [];
      if (gs.nil(userId) || userId == 'NULL')
          return caseSysIdList.toString();

  	var approvers = this.getApprovals(userId);
  	
  	var sysApprovalGR = new GlideRecord('sysapproval_approver');
  	sysApprovalGR.addQuery("state", "!=", "not requested");
  	sysApprovalGR.addNotNullQuery("sysapproval");
  	sysApprovalGR.addQuery("sysapproval.active", true);
  	sysApprovalGR.addQuery("sysapproval.sys_class_name", "INSTANCEOF", "sn_hr_core_case");
  	var query = sysApprovalGR.getEncodedQuery();
  	var qc = sysApprovalGR.addQuery('approver', approvers);
  	// Support granular delegation if available
  	if (GlidePluginManager().isActive('com.glide.granular_service_delegation')) {
  		if (approvers && approvers.length > 1) {
  			qc.addOrCondition('sys_id', 'IN', new hr_Delegation().getDelegatedApprovals({ encoded_query: query }, userId, false)); // Support old delegation with granular delegation
  			sysApprovalGR.query();
  		} else
  			sysApprovalGR = new hr_Delegation().getDelegatedApprovalsGR({ encoded_query: query }, userId, true); // Use API to get assigned and delegated approvals to prevent extra query
  	} else
  		sysApprovalGR.query();
  	
  	while (sysApprovalGR.next())
  		caseSysIdList.push(sysApprovalGR.getValue('sysapproval'));

  	return caseSysIdList.toString();
  },
  
  getApprovals: function(userId) {
  	var approvalsKey = 'userApprovals';
  	if (hr_Utils.hasOwnProperty(approvalsKey) && !gs.nil(hr_Utils[approvalsKey]) && hr_Utils[approvalsKey].hasOwnProperty(userId))
  		return hr_Utils[approvalsKey][userId];

  	hr_Utils[approvalsKey] = {};
  	var userIds = [new String(userId)];
  	var grDelegate = new GlideRecord("sys_user_delegate");
  	grDelegate.addQuery("delegate", userId);
  	grDelegate.addQuery("approvals", true);
  	grDelegate.addQuery("starts", "<=", gs.daysAgo(0));
  	grDelegate.addQuery("ends", ">=", gs.daysAgo(0));
  	grDelegate.query();
  	while (grDelegate.next())
  		userIds.push(grDelegate.getValue('user'));

  	hr_Utils[approvalsKey][userId] = userIds;

  	return userIds;
  },
  
  /* Get a list of case sys_id's for task assignee
   * @param userId {String} (optional) The user sys_id to use for querying
   * @param parentId {String} (optional) The case sys_id to use for querying
   * @return {String} The list of parent sys_id's for the task assignee
   */
  getCaseSysIdForTaskAssignee : function(userId, parentId){
  	var caseMap = {};
  	
  	if (gs.nil(userId) || userId == 'NULL')
  		return caseSysIdList.toString();

  	var hrTask = new GlideRecord('task');
  	
  	// Use property to help reduce the total number of cases returned in the query
  	var queryLimitMonths = gs.getProperty('sn_hr_core.restrict_query.limit_inactive', '');
  	if (queryLimitMonths !== '' && !isNaN(queryLimitMonths) && Number(queryLimitMonths) > -1)
  		hrTask.addQuery('active=true^ORsys_updated_onRELATIVEGT@month@ago@' + Number(queryLimitMonths));
  	
  	if(GlidePluginManager.isActive('com.snc.document_templates'))
  		hrTask.addQuery('sys_class_name','IN','sn_hr_core_task, sn_doc_task');
  	else
  		hrTask.addQuery('sys_class_name', 'sn_hr_core_task');
  	hrTask.addNotNullQuery('parent');
  	
  	if (parentId)
  		hrTask.addQuery('parent', parentId);
  	
  	// Use the current encoded query to add delegated record sys_id's
  	if (GlidePluginManager().isActive('com.glide.granular_service_delegation')) {
  		var grDelegations = new sn_delegation.DelegationUtil().getDelegatedAssignmentsForUser(userId, false, { encoded_query: hrTask.getEncodedQuery() });
  		while (grDelegations.next())
  			caseMap[grDelegations.getValue('parent')] = true;
  	}
  	
  	hrTask.addQuery('assigned_to', userId);
  	hrTask.query();
  	while (hrTask.next())
  		caseMap[hrTask.getValue('parent')] = true;
  	
  	// Return only unique sys_id's
  	var caseList = [];
  	for (var key in caseMap)
  		caseList.push(key);

  	return caseList.toString();
  },

  /*
   * Returns the portal page to redirect to for hr service, sc catalog and order guide task types
   */
  ticketPage: function() {
  	if (new GlidePluginManager().isActive('com.sn_hr_service_portal'))
  		return new sn_hr_sp.hr_PortalUtil().ticketPage();
  },

  cleanupChildRecordsForCase: function(grCase) {
  	if(gs.nil(grCase) || !grCase.isValidRecord())
  		throw new Error("Unable to close the child records since the HR case is invalid");
  	var closeNotes = grCase.getValue("close_notes");
  	
  	var grChildCase = new GlideRecord('sn_hr_core_case');
  	grChildCase.addQuery('parent', grCase.sys_id);
  	grChildCase.addActiveQuery();
  	grChildCase.query();
  	while(grChildCase.next()) {
  		grChildCase.setValue('state', hr_Constants.CASE_CANCELLED);
  		if (!gs.nil(closeNotes))
  			grChildCase.setValue('close_notes', closeNotes);
  		grChildCase.update();
  	}
  	
  	var grChildTask = new GlideRecord('sn_hr_core_task');
  	grChildTask.addQuery('parent', grCase.sys_id);
  	grChildTask.addActiveQuery();
  	grChildTask.query();
  	while(grChildTask.next()) {
  		grChildTask.setValue('state', hr_Constants.TASK_CLOSED_INCOMPLETE);
  		grChildTask.setValue('work_notes', 'Automatically closed because parent case was cancelled');
  		if (!gs.nil(closeNotes))
  			grChildTask.setValue('close_notes', closeNotes);
  		grChildTask.update();
  	}
  },
  
  isEdgeEncryptionActive : function(table, sys_id) {
  	var gr = new GlideRecord(table);
  	gr.get(sys_id);
  	return gr.getED().hasAttachmentsEncrypted() && !gs.isEdgeEncryptedSession();
  },
  
  hasAttachments : function(record) {
  	var gr = record || this._gr;
  	
  	if (gr) {
  		var grAttachment = new GlideRecord('sys_attachment');
  		grAttachment.addQuery('table_name', gr.getRecordClassName());
  		grAttachment.addQuery('table_sys_id', gr.getUniqueValue());
  		grAttachment.setLimit(1);
  		grAttachment.query();

  		return grAttachment.hasNext();
  	}
  	
  	return false;
  },
  
  resetCOEConfig: function() {
  	new sn_hr_core.hr_license().resetCOEConfig();
  },
  
  /*
  * The method is to enable all UA Entitlements
  * The flags Active and User Override will be turned true for all Entitlement belonging to an Application
  * If the User Override == true, 
  *		Skip record
  * Else 
  *		If Active == true
  *			Update User Override = true
  *		Else
  *			Enable all assets of the entitlement in all scopes (HR Core, HR LE, HR SP, HR Integrations)
  *			
  * Update the Inactive tables property
  *
  * @param appId - Application ID (For ex: com.sn_hr_core, com.sn_hr_lifecycle_events)
  */
  enableAllEntitlements: function(appId) {
  	var currInactiveTables = gs.getProperty("sn_hr_core.inactive_tables", "");
  	var tablesToMakeActive = '';
  	
  	var grEntitlement = new GlideRecord('ua_entitlement');
  	grEntitlement.addQuery('user_override', false);
  	grEntitlement.addQuery('app_id', appId);
  	grEntitlement.query();
  	
  	while(grEntitlement.next()) {
  		if(grEntitlement.active){
  			grEntitlement.setValue('user_override', true);
  			grEntitlement.update();
  		} else {
  			this._enableAssetsInAllScopes(grEntitlement.getValue('id'));
  			tablesToMakeActive += grEntitlement.getValue('table_names');
  			tablesToMakeActive += ',';
  		}
  	}
  	
  	if(!gs.nil(currInactiveTables) && !gs.nil(tablesToMakeActive))
  		this._updateInactiveTablesProperty(currInactiveTables, tablesToMakeActive);
  },
  	
  /*
  * The method is to enable all assets for the particular entitlement id
  * Call to Usage Analytics API - sn_lef.GlideEntitlement.enableEntitlement(<entitlement>, <scope>, <disableWorkFlow>) 
  *
  * The call to this API result in enabling assets like Record producers, HR Services, Modules, Topic Cateogries, Topic Detail, Templates
  * The call also updates the Active field = true and User override = true for the entitlement in the ua_entitlement table
  *
  * @param entitlementId (For ex: hr_payroll, hr_total_rewards etc.)
  */
  _enableAssetsInAllScopes: function(entitlementId) {
  	if(GlidePluginManager.isActive('com.sn_hr_core'))
  			sn_lef.GlideEntitlement.enableEntitlement(entitlementId, this.HR_CORE, true);
  			
  	if(GlidePluginManager.isActive('com.sn_hr_integrations'))
  			sn_lef.GlideEntitlement.enableEntitlement(entitlementId, this.HR_INTEGRATIONS, true);
  			
  	if(GlidePluginManager.isActive('com.sn_hr_service_portal'))
  			sn_lef.GlideEntitlement.enableEntitlement(entitlementId, this.HR_SP, true);
  			
  	if(GlidePluginManager.isActive('com.sn_hr_lifecycle_events'))
  			sn_lef.GlideEntitlement.enableEntitlement(entitlementId, this.HR_LE, true);	
  },
  
  /*
  * The method updates the system property sn_hr_core.inactive_tables
  * For new customers, the below method will not be called
  * For upgrading customers, if any custom table is added in the property - it is preserved
  * 
  * @param currInactiveTables - current list of tables in Inactive table property
  * @param tablesToMakeActive - new list of tables that has to be removed from inactive table property
  */
  _updateInactiveTablesProperty: function(currInactiveTables, tablesToMakeActive) {
  	var currTablesArry = currInactiveTables.split(',');
  	var activesTableArry = tablesToMakeActive.split(',');
  	
  	var updatedTablesProp = this._getDiffArray(currTablesArry, activesTableArry).join(',');
  	
  	gs.setProperty("sn_hr_core.inactive_tables", updatedTablesProp);
  },
  
  //Return A - B in the arrays
  _getDiffArray: function(xArray, yArray) {
  	return xArray.filter(function(item) {return yArray.indexOf(item) < 0;});
  },
  
  /*
  * Method returns json object with properties - 'status' and 'message'
  * 
  * @param 
  *	status - status of the result, for ex: 'success', 'error'
  * 	message - status message
  * @return
  *	encoded JSON
  */
  _getStatusMsg: function(status, message) {
  	var retResult = {};
  	retResult['status'] = status;
  	retResult['message'] = message;
  	
  	return new global.JSON().encode(retResult);
  },
  	
  upgradeFulfillmentType : function() {
  	var hrServiceWithLE = false;
  	var hrServiceWithJourney = false;
  	var hrServiceWithApprovers = false;
  	var hrServiceWithActivities = false;
  	var hrServiceWithWorkflow = false;
  	var resultWF;
  	copyApprovalOptions();

  	function copyApprovalOptions() {
  		var gr = new GlideRecord('sn_hr_core_service_activity');
  		if (!gr.isValidField('approval_options'))
  			return;
  		
  		gr.addQuery('activity_type', 'approval');
  		gr.addNullQuery('approval_options');
  		gr.addNotNullQuery('parent_service.approval_options');
  		gr.query();
  		while (gr.next()) {
  			gr.approval_options = gr.parent_service.approval_options;
  			gr.update();
  		}
  	}

  	var hrServiceListWithActivities = getHrServicesWithActivities();
  	var hrService = new GlideRecord('sn_hr_core_service');
  	hrService.addQuery('sys_scope','532da270dad21200a4656ede91f9331e');
  	hrService.query();
  	while (hrService.next()) {				
  		getConditions(hrService);
  		setHRServiceType(hrService);
  		resetConditions();
  	}

  	function getHrServicesWithActivities() {
  		var hrServicesWithActivities = {};
  		var grHRServiceActivity = new GlideAggregate("sn_hr_core_service_activity");
  		grHRServiceActivity.groupBy("parent_service");
  		grHRServiceActivity.query();

  		while (grHRServiceActivity.next())
  			hrServicesWithActivities[grHRServiceActivity.parent_service.sys_id] = true;

  		return hrServicesWithActivities;
  	}

  	function getConditions(grHRService) {
  		if (grHRService.le_type != undefined && grHRService.le_type != '')
  			hrServiceWithLE = true;
  			
  		if (grHRService.journey_config != undefined && grHRService.journey_config != '')
  			hrServiceWithJourney = true;
  		
  		if (grHRService.approval_options != undefined && grHRService.approval_options != '')
  			hrServiceWithApprovers = true;
  		
  		if (hrServiceListWithActivities[grHRService.sys_id] != undefined)
  			hrServiceWithActivities = true;
  		
  		getWorkflow(grHRService.template);
  	}

  	function setHRServiceType(grHRService) {
  		if (hrServiceWithLE && hrServiceWithActivities)
  			grHRService.setValue('fulfillment_type', "custom");
  		else if (hrServiceWithLE && (hrServiceWithApprovers))
  			grHRService.setValue('fulfillment_type', "custom");
  		else if (hrServiceWithActivities && (hrServiceWithApprovers))
  			grHRService.setValue('fulfillment_type', "custom");
  		else if (hrServiceWithActivities)
  			grHRService.setValue('fulfillment_type', "service_activity");
  		else if (hrServiceWithJourney)
  			grHRService.setValue('fulfillment_type', 'journey');
  		else if (hrServiceWithLE)
  			grHRService.setValue('fulfillment_type', "lifecycle_event");
  		else if (hrServiceWithApprovers && hrServiceWithWorkflow) {
  			grHRService.setValue('fulfillment_type', "custom");
  			grHRService.setValue('workflow_detail',resultWF);
  		} else if(hrServiceWithWorkflow){
  			grHRService.setValue('fulfillment_type', "workflow");
  			grHRService.setValue('workflow_detail',resultWF);
  		} else if(hrServiceWithApprovers){
  			grHRService.setValue('fulfillment_type', "custom");
  		} else
  			grHRService.setValue('fulfillment_type', "simple");

  		grHRService.setWorkflow(false);
  		grHRService.update();
  	}

  	function resetConditions() {
  		hrServiceWithLE = false;
  		hrServiceWithJourney = false;
  		hrServiceWithApprovers = false;
  		hrServiceWithActivities = false; 
  		hrServiceWithWorkflow = false;
  	}

  	function getWorkflow(templateSysId){
  		var validateWF =new sn_hr_core.hrFulfillmentTypeUtil();
  		resultWF  = validateWF.getWorkflow(templateSysId);
  		if (resultWF !='')
  			hrServiceWithWorkflow = true;
  	}
  },
  
  setAssignmentType : function() {
  	var grTemplate = new GlideRecord('sn_hr_core_template');
  	// LE Scope Specific tables
  	grTemplate.addEncodedQuery('sys_scope=532da270dad21200a4656ede91f9331e');
  	grTemplate.addQuery('table','!=','sn_hr_core_task');
  	grTemplate.query();
  	while(grTemplate._next()){
  		var grTemplateInfo = grTemplate.template.toString();
  		var assignedToIdx = grTemplateInfo.indexOf("assigned_to");
  		var skillIdx = grTemplateInfo.indexOf("skills");
  		var assignmentGroupIdx = grTemplateInfo.indexOf("assignment_group");
  		if (assignedToIdx > -1)
  			grTemplate.assignment_option = 'named_user';
  		else if (skillIdx > -1 || assignmentGroupIdx > -1)
  			grTemplate.assignment_option = 'skills_group';
  		else 
  			grTemplate.assignment_option = '';
  		grTemplate.setWorkflow(false);
  		grTemplate.update();
  	}
  },

  /*
   * Return value of 'global description' field if populated, else
   * value of 'description' field
   *
   * @param {GlideRecord} gr - an HR Case or HR Task record
   *
   * @returns {(string|undefined)} the description value, undefined if not passed a GlideRecord
   */
  getDescription: function(gr) {
  	if (!gr || typeof gr.getValue !== 'function')
  		return;
  	if( gr.template && gr.template.show_translated_fields)
  		return gr.getDisplayValue("template.description_for_employee");
  	return gr.getValue("rich_description") || GlideStringUtil.escapeHTML(gr.getValue("description"));
  },
  
  /*
   * Return value of 'rich_description' field if populated, else
   * value of 'description' field
   *
   * @param {GlideRecord} gr - an HR Case or HR Task record
   *
   * @returns {(string|undefined)} the description value, undefined if not passed a GlideRecord
   */
  
  getNonGlobalCaseDescription: function(gr) {
  	if (!gr || typeof gr.getValue !== 'function')
  		return;
  	return gr.getValue("rich_description") || GlideStringUtil.escapeHTML(gr.getValue("description"));
  },
  
  /*
  * Returns application scope for table 
  *
  * @param
  *   table: string table name
  * 
  * @returns
  *   success: string value of scope 
  *   failure: empty string 
  */
  getTableScope: function(table) {
  	var tableScope = '';
  	var tableRecord = new GlideRecord('sys_db_object');
  	tableRecord.addQuery('name', table);
  	tableRecord.setLimit(1);
  	tableRecord.query();
  	
  	if (tableRecord.next())
  		tableScope = tableRecord.sys_scope;
  		
  	return tableScope;
  },
  
  /*
  	Wrapper to getAcknowledgeDocument in esign_taskUtils
  */
  getAcknowledgeDocument: function(acknowledgeDocument) {
  	return new sn_esign.esign_taskUtils().getAcknowledgeDocument(acknowledgeDocument);
  },
  
  /* Methods to trigger after the case cancelled or close complete by BR - Cancel or Close Case Cleanup
  */
  
  /* Function closes child tasks,cases, approvals, requested items and workflows associated with given parent case 
  @params
  	grCase - gliderecord of sn_hr_core_case
  	actionName - which action triggered case closure. 
  @return
  	-
  */
  onCaseClose : function(grCase, actionName) {
  	if (gs.nil(grCase) || !grCase.isValidRecord())
  		throw new Error("Unable to close the case since the HR case is invalid");
  	
  	this._renderTaskApprovalsMoot(grCase);

  	if(GlidePluginManager.isActive('com.sn_hr_lifecycle_events')) 
  		// Cancel activity set contexts before canceling the WF to set the context state to 'cancelled'.
  		new sn_hr_le.hr_ActivitySetContextUtil().cancelActivitySetContextsFromCase(grCase.getUniqueValue(), grCase.getValue('state'));
  		
  	this.cancelMyWorkflows(grCase, actionName);
  	this._cancelRequestedItems(grCase);
  	
  	if(GlidePluginManager.isActive('com.sn_lnp'))
  		this._cancelLearningTasks(grCase,actionName);
  		
  	//Schedule asynchronous cleanup if the user may not have access to child cases/tasks
  	if (gs.getUser().getName() == 'system' || new hr_Utils().checkUserHasRole(hr.ROLE_HR_CASE_READER))
  		this.cleanupChildRecordsForCase(grCase); 
  	else
  		gs.eventQueue('sn_hr_core.case_cleanup', grCase); 
  },
  
  _renderTaskApprovalsMoot : function(grCase) {
  	if(gs.nil(grCase) || !grCase.isValidRecord())
  		throw new Error("Invalid input parameter");
  	
  	var gr = new GlideRecord('sysapproval_approver');
  	gr.addQuery('sysapproval', grCase.sys_id); 
  	var qc = gr.addQuery('state', 'requested');
  	qc.addOrCondition('state', 'not requested');
  	gr.setValue('state', 'not_required');
  	gr.updateMultiple();
  },

  cancelMyWorkflows : function(grCase, actionName) {
  	if(gs.nil(grCase) || !grCase.isValidRecord())
  		throw new Error("Invalid input parameter");
  	
  	var wf = new global.Workflow();
  	var gr = wf.getRunningFlows(grCase); 
  	
  	while (gr.next()) 
  		wf.cancelContext(gr);
  },

  _cancelLearningTasks : function(grCase,actionName) {
  	new sn_lc.LearningTaskUtils().closeChildTasks(grCase,actionName);
  },
  
  _cancelRequestedItems : function(grCase) {
  	if(gs.nil(grCase) || !grCase.isValidRecord())
  		throw new Error("Invalid input parameter");
  	
  	var closeNotes = grCase.getValue("close_notes");
  	var grRequest = new GlideRecord('sc_request');
  	grRequest.addQuery('parent', grCase.sys_id); 
  	grRequest.addActiveQuery();
  	grRequest.query();
  	while(grRequest.next()) {
  		grRequest.setValue('request_state', 'closed_cancelled');
  		if (!gs.nil(closeNotes)) {
  			grRequest.setValue('close_notes', closeNotes);
  			var grRequestItem = new GlideRecord('sc_req_item');
  			grRequestItem.addQuery('request', grRequest.getUniqueValue());
  			grRequestItem.query();
  			grRequestItem.setValue('close_notes', closeNotes);
  			grRequestItem.updateMultiple();
  		}
  		grRequest.update();
  	}
  },
  canRenderUIAction :function(caseGr,actionName)
  {
  	if(caseGr.sys_class_name!="sn_hr_er_case")
  		return true;
  	return new sn_hr_er.er_SecurityUtils().canRenderUIAction(caseGr,actionName);		
  },
  
  /* Function to check if adhoc approval action can be shown
  
  @params
  	caseGr - gliderecord of sn_hr_core_case
  @return
  	true - if action can be shown
  	false- if action can not be shown
  */
  
  canShowAdhocApprover : function(caseGr)
  {
  	return hr_ApprovalUtil.isAdhocApprovers(caseGr);
  },

  isExtendedFromCase: function(table) {
  	var tableHierarchy = hr.TABLE_CASE_EXTENSIONS;
  	return tableHierarchy.indexOf(table) !== -1;
  },

  /*
  	Funtion to check whether we can copy attachments or not
  	@param table name
  */
  canCopyAttachments: function(table) {
      // return true to allow copy of attachments from interaction to case
      return this.isExtendedFromCase(table);
  },

  type : 'hr_Utils'
};

hr_Utils.initializeQueryVariables = function() {
  hr_Utils.instance = new hr_Utils();
  hr_Utils.userID = gs.getUserID();

  delete hr_Utils['myCasesWithApprovals'];
  delete hr_Utils['myCasesWithTasks'];
  
  hr_Utils.getMyGroups = function() {
  	return gs.getUser().getMyGroups();
  };
  
  hr_Utils.getMyCasesWithApprovals = function() {
  	if(!hr_Utils.hasOwnProperty('myCasesWithApprovals'))
  		hr_Utils['myCasesWithApprovals'] = hr_Utils.instance.getCaseSysIdListForApprovals(gs.getUserID());
  	return hr_Utils['myCasesWithApprovals'];
  };
  
  hr_Utils.getMyCasesWithTasks = function() {
  	if(!hr_Utils.hasOwnProperty('myCasesWithTasks'))
  		hr_Utils['myCasesWithTasks'] = hr_Utils.instance.getCaseSysIdForTaskAssignee(gs.getUserID());
  	return hr_Utils['myCasesWithTasks'];
  };
};

hr_Utils.initializeQueryVariables();

Sys ID

f65370019f22120047a2d126c42e7000

Offical Documentation

Official Docs: