Name

sn_hr_core.hr_TemplateUtils

Description

No description available

Script

var hr_TemplateUtils = Class.create();
hr_TemplateUtils.prototype = {
  initialize: function() {
      this._appliedTemplates = {};
  },

  /**
   *    applyBefore and applyAfter are intended to be used in conjunction with before and after business rules
   *    This is to prevent overwriting input changes from the user or email/producer/script
   **/

  /* Apply a template to a record only, attempt to prevent overwriting user changes
  * @param templateSysId : sys_id of the template to apply
  * @param record : Optional GlideRecord to apply the template to
  * @param overwrite : Optional Boolean Overwrite record values with template values
  */
  applyBefore: function(templateSysId, record, overwrite) {
      // Setup template and record GlideRecords
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (!templateGr.get(templateSysId) || !templateGr.active)
          return;
      if (!record)
          record = new GlideRecord(templateGr.getValue('table'));
      if (record.isValidField('template'))
          record.setValue('template', templateSysId);
      if (record.isValidField('template_invoked'))
          record.setValue('template_invoked', true);

      // Prepare fields to reset
      var templateData = this._getTemplateData(templateSysId);
      var recordData = {};
      // eslint-disable-next-line guard-for-in
      for (var key in templateData) {
          // Do not reset booleans, as they always have a value
          var fieldElement = record.getElement(key);
          if (!fieldElement || fieldElement.getED().getInternalType() == 'boolean')
              continue;
          if (record.getValue(key))
              recordData[key] = record.getValue(key);
      }

      // Set assigned_to
      var parentField = this._getLinkField(templateGr.getValue('link_element'), record);
      var assignedToValue = this._getAssignedTo(templateGr, record, parentField);
      if (assignedToValue)
          record.setValue('assigned_to', assignedToValue);

      var useAssignmentDate = this._getAssignmentDate(templateGr, record);

      // Set use_assignment_date
      if (useAssignmentDate) {
          record.setValue('use_assignment_date', useAssignmentDate);

          // Set offset fields
          var offsetFields = this._getOffsetFields(templateGr, record);

          if (offsetFields) {
              record.setValue('date_offset_type', offsetFields.date_offset_type);
              record.setValue('date_offset_units', offsetFields.date_offset_units);
              record.setValue('date_offset_quantity', offsetFields.date_offset_quantity);
          }
      } else {
          // Set due_date
          var dueDate = this._getDueDate(templateGr, record, parentField);
          if (dueDate && record.due_date !== null)
              record.due_date.setDateNumericValue(dueDate);
      }

      // Apply template to record
      var template = GlideTemplate.get(templateSysId);
      template.setApplyChildren(false);
      template.apply(record);

      // Reset user input changes
      if (!overwrite)
          for (var field in recordData)
              if (record.getValue(field) != recordData[field])
                  record.setValue(field, recordData[field]);

      return record;
  },

  /* Apply the extensions of a template for a record (eg. children, siblings, template references)
  * @param templateSysId : sys_id of the template to apply
  * @param record : Optional GlideRecord the template was applied to
  */
  applyAfter: function(templateSysId, record) {
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (!templateGr.get(templateSysId) || !templateGr.active || !(record instanceof GlideRecord))
          return;
      var recordSysId = record.getUniqueValue();
      this._appliedTemplates[templateSysId] = recordSysId;

      // Adding checklist
      var templateValue = templateGr.getValue('template');
      if (!gs.nil(templateValue) && templateValue.includes('hr_task_type=checklist'))
          this.applyChecklist(record);

      // Apply children templates
      if (templateGr.getValue('next_child'))
          this._applyChildren(record.getRecordClassName(), recordSysId, templateGr.getValue('next_child'));
  },

  /* Apply a template to a record
  * @param templateSysId : sys_id of the template to apply
  * @param record : Optional GlideRecord to apply the template to
  * @param postCatalogProcess : True if being called by catalog post processing
  */
  apply: function(templateSysId, record, postCatalogProcess) {
      // Setup template and record GlideRecords
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (!templateGr.get(templateSysId) || !templateGr.active)
          return;
      if (!record)
          record = new GlideRecord(templateGr.getValue('table'));
      if (record.isValidField('template'))
          record.setValue('template', templateSysId);
      if (record.isValidField('template_invoked'))
          record.setValue('template_invoked', true);

      // Set assigned to
      var parentField = this._getLinkField(templateGr.getValue('link_element'), record);
      var assignedToValue = this._getAssignedTo(templateGr, record, parentField);
      if (assignedToValue) {
  		/*If this is post-catalog insert, the parent has been changed
  		 This means the assignment group must be voided to allow proper reassignment via the template */
  		var group = record.getValue('assignment_group');
          if (postCatalogProcess && !gs.nil(group) && !new global.HRSecurityUtils().isMemberOfGroup(assignedToValue, group))
  				record.setValue('assignment_group', '');
  		record.setValue('assigned_to', assignedToValue);
  	}

      // Set  use_assignment_date
      var useAssignmentDate = this._getAssignmentDate(templateGr, record);

      if (useAssignmentDate) {
          record.setValue('use_assignment_date', useAssignmentDate);

          // Set offset fields
          var offsetFields = this._getOffsetFields(templateGr, record);

          if (offsetFields) {
              record.setValue('date_offset_type', offsetFields.date_offset_type);
              record.setValue('date_offset_units', offsetFields.date_offset_units);
              record.setValue('date_offset_quantity', offsetFields.date_offset_quantity);
          }
      } else {
          // Set due_date
          var dueDate = this._getDueDate(templateGr, record, parentField);
          if (dueDate && record.due_date !== null)
              record.due_date.setDateNumericValue(dueDate);
      }

      // Apply template to record
      var template = GlideTemplate.get(templateSysId);
      template.setApplyChildren(false);
      template.apply(record);

      var recordUpdate = null;
      if (record.isNewRecord())
          recordUpdate = record.insert();
      else
          recordUpdate = record.update();
      // At any point, if we are unable to insert into a parent table, do not try to insert into the descendant
      // tables.
      if (!recordUpdate)
          return;

      var recordSysId = record.getUniqueValue();
      this._appliedTemplates[templateSysId] = recordSysId;

      // Adding checklist
      if (templateGr.getValue('template').includes('hr_task_type=checklist'))
          this.applyChecklist(record);

      // Apply children templates
      if (templateGr.getValue('next_child'))
          this._applyChildren(record.getRecordClassName(), recordSysId, templateGr.getValue('next_child'));
  },

  /* Apply the children templates
  * @param parentTable : table name of the parent template created record
  * @param parentSysId : sys_id of the parent template created record
  * @param templateSysId : sys_id of the template to apply
  * @param isFutureTask: boolean flag indicates if the record being applied is for future, in that case, do not
  * create the record.
  * @param grFuture: Gliderecord of sn_hr_le_future_todo table
  */
  _applyChildren: function(parentTable, parentSysId, templateSysId, isFutureTask, grFuture) {
      // Detect looping templates - Key could exist while value is empty string or null
      if (this._appliedTemplates.hasOwnProperty(templateSysId))
          return this._appliedTemplates[templateSysId];

      // Add template sys_id to applied templates now to prevent circular dependencies in templates
      this._appliedTemplates[templateSysId] = null;

      // Setup template and record GlideRecords
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (!templateGr.get(templateSysId))
          return;
      var record = new GlideRecord(templateGr.getValue('table'));

      // If this is the template for the selected HR Service, prevent business rule from reapplying template
      var templateHrServiceId = this._getTemplateProperty(templateSysId, 'hr_service');
      if (templateHrServiceId) {
          var serviceGr = new GlideRecord('sn_hr_core_service');
          if (serviceGr.get(templateHrServiceId) && serviceGr.getValue('template') == templateSysId)
              if (record.isValidField('template_invoked'))
                  record.setValue('template_invoked', true);

      }

      // Set parent
      var parentField = this._getLinkField(templateGr.getValue('link_element'), record, parentTable);
      if (parentField)
          record.setValue(parentField, parentSysId);

      // Set assigned to
      var assignedToValue = this._getAssignedTo(templateGr, record, parentField);
      if (assignedToValue)
          record.setValue('assigned_to', assignedToValue);

      // Set use_assignment_date
      var useAssignmentDate = this._getAssignmentDate(templateGr, record);

      if (useAssignmentDate) {
          record.setValue('use_assignment_date', useAssignmentDate);

          // Set offset fields
          var offsetFields = this._getOffsetFields(templateGr, record);

          if (offsetFields) {
              record.setValue('date_offset_type', offsetFields.date_offset_type);
              record.setValue('date_offset_units', offsetFields.date_offset_units);
              record.setValue('date_offset_quantity', offsetFields.date_offset_quantity);
          }
      } else {
          // Set due_date
          var dueDate = this._getDueDate(templateGr, record, parentField);

          if (dueDate && record.due_date !== null)
              record.due_date.setDateNumericValue(dueDate);
      }

      // Apply template to record
      var template = GlideTemplate.get(templateSysId);
      template.setApplyChildren(false);
      template.apply(record);

      //set the template invoked, and template fields. Apply Template (after) BR will be triggered.
      record.setValue('template_invoked', true);
      record.setValue('template', templateSysId);

      // Set template reference
      if (templateGr.getValue('template_reference')) {
          var referenceSysId = this._applyChildren(parentTable, parentSysId,
              templateGr.getValue('template_reference'));

          var templateReferenceGr = new GlideRecord('sn_hr_core_template');
          templateReferenceGr.get(templateGr.getValue('template_reference'));

          var templateReferenceField = this._getLinkField(templateGr.getValue('template_reference_field'), record,
              templateReferenceGr.getValue('table'));
          if (templateReferenceField)
              record.setValue(templateReferenceField, referenceSysId);
      }
      var recordSysId = null;
      if (isFutureTask) {
          var futureJSON = {};
          futureJSON.parent = String(record.getValue(parentField));
          futureJSON.assigned_to_id = String(record.assigned_to);
          futureJSON.assigned_to = String(record.getDisplayValue('assigned_to'));
          futureJSON.assigned_to_display_name = String(record.getDisplayValue('assigned_to'));
          futureJSON.short_description = String(new sn_hr_core.VariableReplacer().replaceFieldTokens(record.short_description,record));
          futureJSON.future = true;
          futureJSON.type = 'task';
          futureJSON.sys_class_name = String(templateGr.table);
          futureJSON.active = true;
          futureJSON.number = 'NA';

          // update the future task with the JSON.
          if (!gs.nil(grFuture)) {
              grFuture.future_json = new global.JSON().encode(futureJSON);
              grFuture.short_description = futureJSON.short_description;
              grFuture.assigned_to = futureJSON.assigned_to;
              grFuture.table_name = futureJSON.sys_class_name;
              grFuture.due_date = new GlideDateTime('2999-01-01 00:00:00');
              grFuture.update();
          }
      } else {
          recordSysId = record.insert();
          this._appliedTemplates[templateSysId] = recordSysId;
      }

      // At any point, if we are unable to insert into a parent table, do not try to insert into the descendent
      // tables.
      if (recordSysId) {
          // Apply sibling templates
          if (templateGr.getValue('next'))
              this._applyChildren(parentTable, parentSysId, templateGr.getValue('next'));
      }

      return recordSysId;
  },

  _getLinkField: function(linkField, recordGr, referenceTableName) {
      if (recordGr.isValidField(linkField))
          return linkField;

      if (!referenceTableName || !recordGr)
          return null;
      var elements = recordGr.getElements();
      for (var i = 0; i < elements.length; i++)
          if (elements[i].getED().getInternalType() == 'reference' &&
              new GlideTableHierarchy(elements[i].getReferenceTable()).getAllExtensions()
                  .indexOf(referenceTableName) != -1)
              return elements[i].getName();

      return null;
  },

  _getAssignedTo: function(templateGr, recordGr, parentField) {
      var assignedToField;
      // Prefer 'assign_to' field, but support legacy 'assigned_to_field'
      if (templateGr.getValue('assign_to')) {
          if (!parentField)
              parentField = 'parent';
          assignedToField = parentField + '.' + templateGr.getValue('assign_to');
      } else if (templateGr.getValue('assigned_to_field'))
          assignedToField = templateGr.getValue('assigned_to_field');
      if (!assignedToField)
          return null;

      // Determine fields to dot walk
      var fields = assignedToField.split('.');
      if (!fields.length || !fields[0])
          return null;

      // Iterate over list of fields to dot walk
      var assignedTo = recordGr[fields[0]];
      if (!assignedTo)
          return null;
      for (var i = 1; i < fields.length; i++) {
          assignedTo = assignedTo[fields[i]];
          if (!assignedTo)
              return null;
      }

      return assignedTo;
  },

  _getDueDate: function(templateGr, recordGr, parentField) {
      var dueDateField;

      if (templateGr.use_assignment_date)
          return null;

      if (templateGr.getValue('due_date_source')) {
          if (!parentField)
              parentField = 'parent';
          dueDateField = parentField + '.' + templateGr.getValue('due_date_source');
      }

      if (!dueDateField)
          return null;

      // Determine fields to dot walk
      var fields = dueDateField.split('.');
      if (!fields.length || !fields[0])
          return null;

      // Iterate over list of fields to dot walk
      var dueDate = recordGr[fields[0]];
      if (!dueDate)
          return null;
      for (var i = 1; i < fields.length; i++) {
          dueDate = dueDate[fields[i]];
          if (!dueDate)
              return null;
      }
      // Apply date offsets, if applicable
      var dateOffsetType = templateGr.getValue('date_offset_type');
      var dateOffsetUnits = templateGr.getValue('date_offset_units');
      var dateOffsetQuantity = templateGr.getValue('date_offset_quantity');

  	return this._getCalculatedDueDate(dueDate, dateOffsetType, dateOffsetUnits, dateOffsetQuantity);
  },

  _getCalculatedDueDate: function(dueDate, dateOffsetType, dateOffsetUnits, dateOffsetQuantity) {
      var gdt = new GlideDateTime();
      gdt.setDisplayValue(dueDate.getDisplayValue());

      if (dateOffsetType == 'on')
          return gdt.getNumericValue();

      var offsetSign = 0;
      if (dateOffsetType == 'before')
          offsetSign = -1;
      else if (dateOffsetType == 'after')
          offsetSign = 1;
      else
          return null;

      var offsetTime = offsetSign * dateOffsetQuantity;

      if (dateOffsetUnits == 'hours')
          gdt.addSeconds(offsetTime * 3600);
      else if (dateOffsetUnits == 'days')
          gdt.addDaysLocalTime(offsetTime);
      else if (dateOffsetUnits == 'weeks')
          gdt.addWeeksLocalTime(offsetTime);
      else if (dateOffsetUnits == 'months')
          gdt.addMonthsLocalTime(offsetTime);
      return gdt.getNumericValue();
  },

  _getTemplateData: function(templateSysId) {
      var templateData = {};

      var templateGr = new GlideRecord('sn_hr_core_template');
      // validate if the template exists and active
      if (templateGr.get(templateSysId) && templateGr.active && !gs.nil(templateGr.getValue('template'))) {
          var templateFields = templateGr.getValue('template').split('^');
          for (var i = 0; i < templateFields.length; i++) {
              // Determine split to be first "=" to allow additional  "="'s in field value
              var splitIndex = templateFields[i].indexOf('=');
              if (splitIndex > 0) {
                  var field = templateFields[i].substring(0, splitIndex);
                  var fieldValue = templateFields[i].substring(splitIndex + 1, templateFields[i].length);
                  templateData[field] = {
                      value: fieldValue,
                      displayValue: this._getTemplatesFieldDisplayValue(field, fieldValue, templateGr)
                  };
              }
          }
      }
      return templateData;
  },

  _getTemplatesFieldDisplayValue: function(field, value, templateGr) {
      var templateForTable = String(templateGr.table);
      return new hr_CoreUtils().getFieldsDisplayValue(field, value, templateForTable);
  },

  _getTemplateProperty: function(templateSysId, field) {
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (templateGr.get(templateSysId) && templateGr.getValue('template')) {
          var templateFields = templateGr.getValue('template').split('^');
          for (var i = 0; i < templateFields.length; i++) {
              // Determine split to be first "=" to allow additional "="'s in field value
              var splitIndex = templateFields[i].indexOf('=');
              // Check if this is desired field
              if (splitIndex > 0 && templateFields[i].substring(0, splitIndex) == field)
                  return templateFields[i].substring(splitIndex + 1, templateFields[i].length); // return field value
          }
      }

      return null;
  },

  /* Return array of active COE table names
  */
  process: function() {
      var tables = [];
      var inactiveTables = gs.getProperty('sn_hr_core.inactive_tables', '').split(',');

      // Add non-inactive sn_hr_core_case tables
      var caseTables = hr.TABLE_CASE_EXTENSIONS;
      for (var i = 0; i < caseTables.length; i++)
          if (inactiveTables.indexOf(caseTables[i]) == -1)
              tables.push(caseTables[i].toString());

      // Add non-inactive sn_hr_core_task tables
      var taskTables = hr.TABLE_TASK_EXTENSIONS;
      for (i = 0; i < taskTables.length; i++)
          if (inactiveTables.indexOf(taskTables[i]) == -1)
              tables.push(taskTables[i].toString());

  	if (GlidePluginManager.isActive('com.snc.document_templates'))
  		tables.push('sn_doc_task');

  	var additionalTables = this.getAdditionalTables();
  	additionalTables.forEach(function(tableName){
  		if(tables.indexOf(tableName) > -1)
  			return;
  		tables.push(tableName);
  	});
      return tables;
  },
  /*
  Functionality: Calls extension point to add tables to the list of Task Table field in Activity Configuration Table
  @return: array of tables
  */
  getAdditionalTables: function() {
  	var tables=[];
  	if(GlidePluginManager.isActive('com.sn_hr_lifecycle_ent')){
  		try{
  			var eps = new GlideScriptedExtensionPoint().getExtensions("HRTemplateTableOptions");
  			eps.forEach(function(ep){
  				var additionalTables = ep.getAdditionalTables();
  				additionalTables.forEach(function(tableName){
  					if(tables.indexOf(tableName) > -1)
  						return;
  					var gr = new GlideRecord(tableName);
  					if(gr.isValid())
  						tables.push(tableName);
  				});
  			});
  		}
  		catch(ex){
  			gs.error("Adding additional table option failed for HR templates "+ ex.message);
  		}
  	}
  	return tables;
  },

  /*
  * @parm record: Record to which checklist will be applied.
  * @parm templateId: (optional) sys_id of the HR Template (eg. This is used for records without an hr_service field)
  *
  * Functionality: Applies a checklist to a record based on sn_hr_core_service or sn_hr_core_template.
  */
  applyChecklist: function(record, templateId) {
      // Table containing the reference to the checklist record
      var checklistLinkTable = (record.getValue('hr_service')) ? 'sn_hr_core_service' : 'sn_hr_core_template';
      // Field referencing the checklist record
      var checklistLinkField = (record.getValue('hr_service')) ? 'hr_service' : 'template';
      // sys_id of the record that references the checklist record
      var checklistLinkSysId = templateId || record.getValue(checklistLinkField);

      var checklistLinkTableGr = new GlideRecord(checklistLinkTable);
      if (checklistLinkTableGr.get(checklistLinkSysId)) {
          var cl = new GlideRecord('checklist');
          cl.addQuery('table', checklistLinkTable);
          cl.addQuery('document', checklistLinkSysId);
          cl.query();
          if (cl.next()) {
              // Copy checklist and checklist items to record
              var newCl = new GlideRecord('checklist');
              newCl.setValue('table', record.getTableName());
              newCl.setValue('document', record.getUniqueValue());
              var checkListId = newCl.insert();
              if (gs.nil(checkListId))
                  return;

              var newClItem = new GlideRecord('checklist_item');
              newClItem.addQuery('checklist', cl.getUniqueValue());
              newClItem.orderBy('order');
              newClItem.query();
              while (newClItem.next()) {
                  newClItem.setValue('checklist', checkListId);
                  newClItem.insert();
              }
          }
      }
  },
  _getAssignmentDate: function(templateGr, record) {

      if (templateGr.table && templateGr.table == 'sn_hr_core_task')
          return templateGr.use_assignment_date;
      return null;
  },
  _getOffsetFields: function(templateGr, record) {
      if (templateGr.table && templateGr.table == 'sn_hr_core_task')
          return {
              'date_offset_type': templateGr.date_offset_type,
              'date_offset_units': templateGr.date_offset_units,
              'date_offset_quantity': templateGr.date_offset_quantity
          };

      return null;
  },

  /* Apply a template to a record. This method is specifc to document task template
  * @param templateSysId : sys_id of the document task template to apply
  * @param record : Optional GlideRecord to apply the template to
  * @return docTask: document task record
  */
  applyDocumentTaskTemplate: function(templateSysId, record) {
  	var docTaskId;
      var templateGr = new GlideRecord('sn_hr_core_template');
      if (!templateGr.get(templateSysId) || !templateGr.active || templateGr.getValue('table')!='sn_doc_task')
          return;
      if (!record)
          record = new GlideRecord('sn_doc_task');

      // Apply template to record
      var template = GlideTemplate.get(templateSysId);
      template.setApplyChildren(false);
      template.apply(record);

  	var dueDate;
      if (templateGr.use_assignment_date) {
          var currentDate = new GlideDateTime();
  		dueDate = this._getCalculatedDueDate(currentDate,templateGr.date_offset_type,
  											 templateGr.date_offset_units,templateGr.date_offset_quantity);
      } else
  		dueDate = this._getDueDate(templateGr, record);

  	if (!gs.nil(dueDate))
  		record.due_date.setDateNumericValue(dueDate);

  	return record;
  },

  /* Check whether the given table is one of the active HR Case Tables
  * @param {String} tableName : Name of the table that we need to check
  * @return {boolean}: Returns true if given table is one of the active HR Case Tables
  */

  checkHRCaseTables: function(tableName) {
      var inactiveTables = gs.getProperty('sn_hr_core.inactive_tables', '').split(',');

      //Check non-inactive sn_hr_core_case tables
      var caseTables = hr.TABLE_CASE_EXTENSIONS;
      for (var i = 0; i < caseTables.length; i++)
          if (inactiveTables.indexOf(caseTables[i]) == -1 && caseTables[i] == tableName)
              return true;
  	return false;
  },

  /* Check whether the given table is one of the HR Task Tables
  * @param {String} tableName : Name of the table that we need to check
  * @return {boolean}: Returns true if given table is one of the HR Task Tables
  */
  checkHRTaskTables: function(tableName) {
      var taskTables = hr.TABLE_TASK_EXTENSIONS;
  	for(var i = 0; i < taskTables.length; i++)
  		if(taskTables[i] == tableName)
  			return true;
  	return false;
  },

  type: 'hr_TemplateUtils'
};

Sys ID

d9f16db02f321200b3c9a310c18c959e

Offical Documentation

Official Docs: