Name

sn_hr_core.hr_Synchronize

Description

Functionality for Synchronizing the HR Profile and User tables

Script

var hr_Synchronize = Class.create();
hr_Synchronize.prototype = {
  initialize: function() {
  	// Support extension points via config method returning string?
  },
  
  /* Synchronize data between the sys_user and the sn_hr_core_profile table
   * @param gr - GlideRecord - The record to synchronize changes from
   * @param syncAllFields - boolean - Whether to sync all fields or just changed fields
   */
  syncRecord: function(gr, syncAllFields) {
  	if (!gr || !gr.isValid())
  		return;
  	
  	var tableName = gr.getTableName();

  	if (tableName == hr.TABLE_PROFILE) {
  		var grUser = new GlideRecord(hr.TABLE_USER);
  		if (gr.user.nil() || !grUser.get(gr.getValue('user')) || !grUser.canWrite())
  			return;

  		var profileExclusionList = gs.getProperty('sn_hr_core.sync.exclusion_fields.profile', '').replace(/\s/g, '').split(',');
  	
  		var profileMap = {
  			'address': { 'destField': 'street' },
  			'country': { 'destField': 'country', 'func': this._mapProfileField },
  			'position': { 'destField': 'title', 'func': this._mapProfileField },
  			'source': { 'destField': 'hr_integration_source' }
  		};
  		
  		this._syncFields(gr, grUser, profileExclusionList, profileMap, this._getChangedFields(gr, syncAllFields));
  		
  	} else if (tableName == hr.TABLE_USER) { 
  		var grProfile = new GlideRecord(hr.TABLE_PROFILE);
  		grProfile.addQuery('user', gr.getUniqueValue());
  		grProfile.query();
  		if (!grProfile.next() || !grProfile.canWrite())
  			return;
  		
  		var userExclusionList = gs.getProperty('sn_hr_core.sync.exclusion_fields.sys_user', '').replace(/\s/g, '').split(',');

  		var userMap = {
  			'country': { 'destField': 'country', 'func': this._mapUserField },
  			'hr_integration_source': { 'destField': 'source' },
  			'street': { 'destField': 'address' },
  			'title': { 'destField': 'position', 'func': this._mapUserField }
  		};
  		
  		this._syncFields(gr, grProfile, userExclusionList, userMap, this._getChangedFields(gr, syncAllFields));
  	}
  },
  
  /* Synchronize a new record
   * @param gr - GlideRecord - The record to synchronize changes from
   * @return [GlideRecord] - The created record, or null if not created
   */
  syncNewRecord: function(gr) {
  	if (!gr || !gr.isValid())
  		return null;
  	
  	if (gr.getTableName() == hr.TABLE_USER) {
  		//profile creation can be triggered by case creation and relies on not checking ACLs
  		var grProfile = new GlideRecord(hr.TABLE_PROFILE);
  		grProfile.setValue('user', gr.getUniqueValue());

  		// Support excluding fields from profile creation based on sync property
  		var userExclusionList = gs.getProperty('sn_hr_core.sync.exclusion_fields.create_profile', '').replace(/\s/g, '').split(',');
  		// Map of user field to profile field
  		var userMap = {
  			'phone': { 'destField': 'work_phone' },
  			'mobile_phone': { 'destField': 'work_mobile' },
  			'email': { 'destField': 'personal_email' }
  		};
  		
  		this._syncFields(gr, grProfile, userExclusionList, userMap, Object.keys(userMap));
  		
  		if (!grProfile.isValidRecord())
  			return null;
  		
  		return grProfile;
  	}
  	
  	return null;
  },
  
  /*
   * Return an Array of fields that have changed in a GlideRecord, ignoring virtual and system fields
   * @param grSrc - GlideRecord - The record to copy field-GlideElement pairs from
   * @param copyAllFields - boolean - Determine if all fields should be copied
   * @return Array[String] - Array of fields that have changed
   */
  _getChangedFields: function(grSrc, copyAllFields) {
  	// TODO should this take exclusionList as a parameter to front load exclusions?
  	var changedFields = [];
  	var fields = grSrc.getElements();
  	for (var i = 0; i < fields.length; i++) {
  		var element = fields[i];
  		if (copyAllFields || element.changes()) {
  			var ed = element.getED();
  			var eleName = element.getName();
  			if (!ed.isVirtual() && !ed.isAutoOrSysID() && !eleName.startsWith('sys_')) // sys_domain is not covered by isAutoOrSysID api
  				changedFields.push(eleName);
  		}
  	}
  	
  	return changedFields;
  },
  
  /* Sync fields between GlideRecord objects with field map
  * @param grSrc - GlideRecord - The record to synchronize fields from
  * @param grDest - GlideRecord - The record to synchronize fields to
  * @param exclusionList - Array - List of fields (strings) to ignore when synchronizing records
  * @param map - Object - Map of field names on source record that correspond to non-identical fields on destination record
  * @param fields - Array[String] - Array of fields to synchronize
  */
  _syncFields: function(grSrc, grDest, exclusionList, map, fields) {
  	for (var i = 0; i < fields.length; i++) {
  		var field = fields[i];
  		if (exclusionList.indexOf(field) > -1)
  			continue;
  		
  		if (map.hasOwnProperty(field)) {
  			if (map[field].hasOwnProperty('func'))
  				map[field]['func'](grSrc, grDest, field, map[field]['destField']);
  			else 
  				this._simpleMap(grSrc, grDest, field, map[field]['destField']);
  		} else 
  			this._simpleMap(grSrc, grDest, field, field);
  	}
  	
  	grDest.update();
  },
  
  /* A simple field mapping function
  * @param grSrc - GlideRecord - The record to synchronize fields from
  * @param grDest - GlideRecord - The record to synchronize fields to
  * @param srcField - String - The name of the field to synchronize from
  * @param destField - String - The name of the field to synchronize to
  */
  _simpleMap: function(grSrc, grDest, srcField, destField) {
  	if (grSrc.isValidField(srcField) && grDest.isValidField(destField)){
  		var srcValue = grSrc.getElement(srcField).getED().isEncrypted() ? grSrc.getDisplayValue(srcField) : grSrc.getValue(srcField);
  		srcValue = gs.nil(srcValue) ? "" : srcValue;
  		if (grDest.getElement(destField).getED().isEncrypted())
  			grDest.getElement(destField).setDisplayValue(srcValue);
  		else
  			grDest.setValue(destField, srcValue);
  	}
  },
  
  /* Special handling for certain profile field mappings
  * @param grSrc - GlideRecord - The record to synchronize fields from
  * @param grDest - GlideRecord - The record to synchronize fields to
  * @param srcField - String - The name of the field to synchronize from
  * @param destField - String - The name of the field to synchronize to
  */
  _mapProfileField: function(grSrc, grDest, srcField, destField) {
  	if (srcField == 'position') {
  		var grPosition = new GlideRecord('sn_hr_core_position');
  		if (grPosition.get(grSrc.getElement(srcField).toString()))
  			grDest.setValue(destField, grPosition.getDisplayValue());
  		
  	} else if (srcField == 'country') {
  		var grCountry = new GlideRecord('core_country');
  		if (grCountry.get(grSrc.getElement(srcField).toString()))
  			grDest.setValue(destField, grCountry.getValue('iso3166_2'));
  	}
  },
  
  /* Special handling for certain user field mappings
  * @param grSrc - GlideRecord - The record to synchronize fields from
  * @param grDest - GlideRecord - The record to synchronize fields to
  * @param srcField - String - The name of the field to synchronize from
  * @param destField - String - The name of the field to synchronize to
  */
  _mapUserField: function(grSrc, grDest, srcField, destField) {
  	if (srcField == 'title') {
  		// TODO If the title field was set from the translated value of the hr position, then you cannot reverse search for it?
  		var grPosition = new GlideRecord('sn_hr_core_position');
  		if (grPosition.get('position', grSrc.getElement(srcField).toString()))
  			grDest.setValue(destField, grPosition.getUniqueValue());
  		
  	} else if (srcField == 'country') {
  		var grCountry = new GlideRecord('core_country');
  		if (grCountry.get('iso3166_2', grSrc.getElement(srcField).toString()))
  			grDest.setValue(destField, grCountry.getUniqueValue());
  	}
  	
  	// TODO original method calls setWorkflow(false) and updates immediately
  },
  
  type: 'hr_Synchronize'
};

Sys ID

6c2dea1b53da0010a9e7ddeeff7b12c2

Offical Documentation

Official Docs: