Name

global.SLAUtilSNC

Description

Reusable helper classes for use within the SLA application

Script

var SLAUtilSNC = Class.create();

SLAUtilSNC.HISTORY_WALKER_COUNTER = 0;

SLAUtilSNC.prototype = {
  TABLE_TASK_SLA: 'task_sla',
  TABLE_CMN_SCHEDULE: 'cmn_schedule',
  TABLE_CONTRACT_SLA: 'contract_sla',
  TABLE_SERVICE_OFFERING_SLA: 'service_offering_sla',
  ATTR_STAGE: 'stage',
  ATTR_BUSINESS_PERCENTAGE: 'business_percentage',
  ATTR_BUSINESS_DURATION: 'business_duration',
  ATTR_BUSINESS_TIME_LEFT: 'business_time_left',
  ATTR_BUSINESS_PAUSE_DURATION: 'business_pause_duration',
  ATTR_PERCENTAGE: 'percentage',
  ATTR_DURATION: 'duration',
  ATTR_TIME_LEFT: 'time_left',
  ATTR_PAUSE_DURATION: 'pause_duration',
  ATTR_START_TIME: 'start_time',
  ATTR_HAS_BREACHED: 'has_breached',
  ATTR_PLANNED_END_TIME: 'planned_end_time',
  ATTR_COLLECTION: 'collection',
  ATTR_SERVICE_COMMITMENT: 'service_commitment',
  TABLE_SYS_CHOICE: 'sys_choice',
  FIELD_TYPE_FIELD_NAME: 'field_name',
  FIELD_TYPE_WF: 'workflow',
  ATTR_NAME: 'name',
  ATTR_INACTIVE: 'inactive',
  ATTR_LANGUAGE: 'language',
  ATTR_ELEMENT: 'element',
  ATTR_TASK: 'task',
  DATE_FORMAT_DISPLAY_VALUE_INTERNAL: 'display_value_internal',
  DATE_FORMAT_DISPLAY_VALUE: 'display_value',
  DATE_FORMAT_VALUE: 'value',
  LOG_PROPERTY: 'com.snc.sla.util.log',
  SLA_ALWAYS_RUN_RELDUR_SCRIPT_PROPERTY: 'com.snc.sla.calculation.always_run_relative_duration_script',
  HISTORY_WALKER_USE_AUDIT_PREFIX_PROPERTY: 'com.snc.sla.history_walker.use_audit.',
  SLA_ADV_COND_NONE: 'none',
  SLA_ADV_COND_ADV_ONLY: 'advanced',
  SLA_ADV_COND_ADV_WITH_JOURNAL: 'advanced_journal',
  SLA_ADV_COND_ADV_WITH_SYSTEM: 'advanced_system',
  SLA_ADV_COND_ADV_WITH_JOURNAL_AND_SYSTEM: 'advanced_journal_and_system',
  ADV_CONDITION_TYPE: 'adv_condition_type',
  ON_CONDITION: 'on_condition',
  CANCEL_CONDITION: 'cancel_condition',
  RESUME_CONDITION: 'resume_condition',
  WHEN_TO_CANCEL: 'when_to_cancel',
  WHEN_TO_RESUME: 'when_to_resume',
  WITH_SYSTEM_FIELDS: [
  	'sys_mod_count',
  	'sys_updated_by',
  	'sys_updated_on'
  ],
  IGNORE_UNAUDITED: { "sys_tags": true },
  SLA_UPDATE_SOURCE_ENGINE_PARAMETER: "sla_update_source",
  SYS_AUDIT: 'sys_audit',
  TABLENAME: 'tablename',
  DOCUMENTKEY: 'documentkey',
  RECORD_CHECKPOINT: 'record_checkpoint',
  MAX: 'MAX',

  initialize: function() {
  	this.gru = new GlideRecordUtil();
  	this._log = new GSLog(this.LOG_PROPERTY, this.type);
  	this.alwaysRunRelDurScript = (gs.getProperty(this.SLA_ALWAYS_RUN_RELDUR_SCRIPT_PROPERTY, 'false') === 'true');
  },

  getMaxUpdateCount: function(tableName, documentKey) {
  	var ga = new GlideAggregate(this.SYS_AUDIT);
  	ga.addQuery(this.DOCUMENTKEY, documentKey);
  	ga.setGroup(false);
  	ga.setOrder(false);
  	ga.addAggregate(this.MAX, this.RECORD_CHECKPOINT);
  	ga.query();
  	if (ga.next())
  		return parseInt(ga.getAggregate(this.MAX, this.RECORD_CHECKPOINT));
  	return 0;
  },

  getSchedule: function(contractSLAGr, taskGr) {
  	if (!contractSLAGr) {
  		if (this._log.atLevel(GSLog.DEBUG))
  			this._log.debug('[getSchedule]: Invalid contractSLAGr param. Returning null');

  		return null;
  	}

  	var scheduleGR = new GlideRecord(this.TABLE_CMN_SCHEDULE);
  	var schSource = contractSLAGr.getValue('schedule_source') || '';
  	var tzSource = contractSLAGr.getValue('timezone_source') || '';
  	var taskSLAGr = new GlideRecord(this.TABLE_TASK_SLA);
  	taskSLAGr.initialize();

  	if (taskGr && taskGr.sys_id)
  		taskSLAGr.task = taskGr.sys_id; //do not use getUniqueValue() as dummy records created from audit in SLATimeline will have different value.

  	taskSLAGr.sla = contractSLAGr.getUniqueValue();
  	var scheduleId = SLASchedule.source(schSource, taskSLAGr, taskGr);

  	if (scheduleId)
  		scheduleGR.get(scheduleId);

  	var tz = scheduleGR.getValue('time_zone') || SLATimezone.source(tzSource, taskSLAGr, taskGr) || gs.getSysTimeZone();

  	return new GlideSchedule(scheduleGR.sys_id, tz);
  },

  copyGlideRecord: function(gr) {
  	if (!gr || !(gr.sys_id || gr.original_sys_id)) {
  		if (this._log.atLevel(GSLog.DEBUG))
  			this._log.debug('[copyGlideRecord] invalid gr param');

  		return null;
  	}

  	var sysId = gr.original_sys_id || gr.sys_id;
  	var copiedGr = new GlideRecord(gr.getRecordClassName());
  	copiedGr.initialize();
  	copiedGr.setNewGuidValue(sysId);
  	var fields = gr.getFields();
  	if (sysId) {
  		copiedGr.original_sys_id = sysId;
  		copiedGr.sys_id = sysId;
  	}

  	for (var i = 0; i < fields.size(); i++) {
  		var fieldName = fields.get(i).getName();
  		copiedGr.setValue(fieldName, gr.getValue(fieldName));
  	}

  	for (var field in gr.variables)
  		copiedGr.variables[field] = gr.variables[field];

  	return copiedGr;
  },

  getChangedFields: function(gr) {
  	var changedFields = [];

  	if (!gr || !(gr.sys_id || gr.original_sys_id)) {
  		if (this._log.atLevel(GSLog.DEBUG))
  			this._log.debug('[getChangedFields] invalid gr param');

  		return changedFields;
  	}

  	var fields = gr.getFields();
  	var field;
  	for (var i = 0; i < fields.size(); i++) {
  		field = fields.get(i);
  		if (field.getName() === 'variables')
  			continue;

  		if (field.changes())
  			changedFields.push(field);
  	}
  	return changedFields;
  },

  getChangedVariables: function(gr) {
  	var changedVariables = [];

  	var isInvalidGr = !gr || !(gr.sys_id || gr.original_sys_id);
  	if (isInvalidGr || !gr.isValidField('variables') || !gr.variables.changes()) {
  		if (this._log.atLevel(GSLog.DEBUG))
  			this._log.debug('[getChangedVariables] invalid gr param, or gr has no variables or variable changes');

  		return changedVariables;
  	}

  	for (var variableName in gr.variables) {
  		if (gr.variables[variableName].changes())
  			changedVariables.push(variableName);
  	}

  	return changedVariables;
  },

  grToJsArr: function(gr, checkReadAccess) {
  	var arr = [];

  	while (gr.next())
  		arr.push(this.grToJsObj(gr, checkReadAccess));

  	return arr;
  },

  grToJsObj: function(gr, checkReadAccess) {
  	var obj = {};
  	obj.sys_id = gr.getUniqueValue();
  	if (!checkReadAccess || (checkReadAccess && gr.canRead())) {
  		var fields = gr.getFields();
  		obj.read_allowed = true;
  		for (var i = 0; i < fields.size(); i++) {
  			var fieldName = fields.get(i).getName();
  			obj[fieldName] = {};
  			var fieldAccess = !checkReadAccess || (checkReadAccess && gr.getElement(fieldName).canRead());
  			obj[fieldName].label = gr.getElement(fieldName).getLabel();
  			if (fieldAccess) {
  				obj[fieldName].read_allowed = true;
  				obj[fieldName].value = gr.getValue(fieldName);
  				if (gr.getRecordClassName() == this.TABLE_CONTRACT_SLA && gr[fieldName].getED().getInternalType() == this.FIELD_TYPE_FIELD_NAME) {
  					var collectionName = gr.getValue(this.ATTR_COLLECTION);
  					if (collectionName && obj[fieldName].value)
  						obj[fieldName].display_value = new GlideCompositeElement(obj[fieldName].value, collectionName).getFullLabel();
  				} else if (gr[fieldName].getED().getInternalType() == this.FIELD_TYPE_WF) {
  					//Workaround to avoid workflow fields wiping out rest of the values.
  					//A PRB is being logged with platform for root cause and fix. Refer PRB748550 work notes
  					var tempGr = new GlideRecord(gr.getRecordClassName());
  					tempGr.initialize();
  					tempGr.setValue(fieldName, gr.getValue(fieldName));
  					obj[fieldName].display_value = tempGr.getDisplayValue(fieldName);
  				} else {
  					var ed = gr.getElement(fieldName).getED();
  					// skip journal fields
  					if (!(ed.isJournal() || ed.isJournalList()))
  						obj[fieldName].display_value = gr.getDisplayValue(fieldName);
  				}
  				if (gr[fieldName] != null && gr[fieldName].getGlideObject() && gr[fieldName]
  					.getGlideObject().getDisplayValueInternal()) {
  					obj[fieldName].display_value_internal = gr[fieldName].getGlideObject().getDisplayValueInternal();
  				}
  			} else {
  				obj[fieldName].read_allowed = false;
  				obj[fieldName].value = undefined;
  				obj[fieldName].display_value = gs.getMessage('(restricted)');
  			}
  		}
  		if (!obj.variables)
  			obj.variables = {};
  		if (gr.variables.canRead()) {
  			for (var field in gr.variables) {
  				obj.variables[field] = {};
  				obj.variables[field].read_allowed = true;
  				obj.variables[field].value = gr.variables[field].getValue();
  				obj.variables[field].display_value = gr.variables[field].getDisplayValue();
  			}
  		} else {
  			for (var fieldVar in gr.variables) {
  				obj.variables[fieldVar] = {};
  				obj.variables[fieldVar].read_allowed = false;
  				obj.variables[fieldVar].value = undefined;
  				obj.variables[fieldVar].display_value = gs.getMessage('(restricted)');
  			}
  		}
  	} else {
  		obj.read_allowed = false;
  		obj.security_check_fail_message = gs.getMessage('Security constraints restrict read access to this {0}', gr.getRecordClassName());
  	}
  	return obj;
  },

  getFieldColumnMap: function() {
  	var gr = new GlideRecord(this.TABLE_TASK_SLA);
  	var displayColumns = {};
  	displayColumns[this.ATTR_STAGE] = gr.getElement(this.ATTR_STAGE).getLabel();
  	displayColumns[this.ATTR_BUSINESS_PERCENTAGE] = gr.getElement(this.ATTR_BUSINESS_PERCENTAGE).getLabel();
  	displayColumns[this.ATTR_BUSINESS_DURATION] = gr.getElement(this.ATTR_BUSINESS_DURATION).getLabel();
  	displayColumns[this.ATTR_BUSINESS_TIME_LEFT] = gr.getElement(this.ATTR_BUSINESS_TIME_LEFT).getLabel();
  	displayColumns[this.ATTR_BUSINESS_PAUSE_DURATION] = gr.getElement(this.ATTR_BUSINESS_PAUSE_DURATION).getLabel();
  	displayColumns[this.ATTR_PERCENTAGE] = gr.getElement(this.ATTR_PERCENTAGE).getLabel();
  	displayColumns[this.ATTR_DURATION] = gr.getElement(this.ATTR_DURATION).getLabel();
  	displayColumns[this.ATTR_TIME_LEFT] = gr.getElement(this.ATTR_TIME_LEFT).getLabel();
  	displayColumns[this.ATTR_PAUSE_DURATION] = gr.getElement(this.ATTR_PAUSE_DURATION).getLabel();
  	displayColumns[this.ATTR_START_TIME] = gr.getElement(this.ATTR_START_TIME).getLabel();
  	displayColumns[this.ATTR_HAS_BREACHED] = gr.getElement(this.ATTR_HAS_BREACHED).getLabel();
  	displayColumns[this.ATTR_PLANNED_END_TIME] = gr.getElement(this.ATTR_PLANNED_END_TIME).getLabel();
  	return displayColumns;
  },

  isTaskSlaAttached: function(taskSysId) {
  	var gr = new GlideRecord(this.TABLE_TASK_SLA);
  	gr.addQuery(this.ATTR_TASK, taskSysId);
  	gr.setLimit(1);
  	gr.query();
  	return gr.getRowCount() > 0;
  },

  getSlaStagesMap: function() {
  	var stages = [];
  	var gr = new GlideRecord(this.TABLE_SYS_CHOICE);
  	gr.addQuery(this.ATTR_NAME, this.TABLE_TASK_SLA);
  	gr.addQuery(this.ATTR_ELEMENT, this.ATTR_STAGE);
  	var qc = gr.addNullQuery(this.ATTR_INACTIVE);
  	qc.addOrCondition(this.ATTR_INACTIVE, 'false');
  	gr.addQuery(this.ATTR_LANGUAGE, gs.getUser().getLanguage());
  	gr.query();
  	while (gr.next()) {
  		stages.push({
  			label: gr.getValue('label'),
  			value: gr.getValue('value')
  		});
  	}
  	return stages;
  },

  getRelatedFieldsFromEncodedQuery: function(table, encodedQuery) {
  	var queryString = new GlideQueryString(table, encodedQuery);
  	queryString.deserialize();
  	var relatedFields = [];
  	var queryTerms = queryString.getTerms();
  	for (var i = 0; i < queryTerms.size(); i++) {
  		if (queryTerms.get(i).getTermField() && relatedFields.indexOf(queryTerms.get(i).getTermField() + '') < 0)
  			relatedFields.push(queryTerms.get(i).getTermField() + '');
  	}
  	return relatedFields;
  },

  populateDateInCommonFormatsAndConversions: function(dateStr, format /*value, display_value, display_value_internal*/) {
  	if (dateStr && format) {
  		var gdt = new GlideDateTime();
  		if (format == this.DATE_FORMAT_DISPLAY_VALUE_INTERNAL)
  			gdt.setDisplayValueInternal(dateStr);
  		else if (format == this.DATE_FORMAT_DISPLAY_VALUE)
  			gdt.setDisplayValue(dateStr);
  		else if (format == this.DATE_FORMAT_VALUE)
  			gdt.setValue(dateStr);
  		return {
  			value: gdt.getValue(),
  			display_value: gdt.getDisplayValue(),
  			display_value_internal: gdt.getDisplayValueInternal()
  		};
  	}
  },

  _supportPolarisURL: function() {
  	var usePolaris = sn_ui.PolarisUI.isEnabled();
  	return (usePolaris) ? '&sysparm_use_polaris=true' : '';
  },

  getGlideStackURL: function(stackName) {
  	var stack = gs.getSession().getStack(stackName);
  	return {
  		url: stack.back() + this._supportPolarisURL()
  	};
  },

  setGlideStackURL: function(url, stackName) {
  	var stack = gs.getSession().getStack(stackName);
  	var stackUrl = stack.push(url);
  	return {
  		url: stackUrl + this._supportPolarisURL()
  	};
  },

  duplicateLastUrlInGlideStack: function(stackName) {
  	var stack = gs.getSession().getStack(stackName);
  	var stackUrl = stack.push(stack.top());
  	return {
  		url: stackUrl + this._supportPolarisURL()
  	};
  },

  getTopGlideStackURL: function(stackName) {
  	var stack = gs.getSession().getStack(stackName);
  	return {
  		url: stack.top() + this._supportPolarisURL()
  	};
  },

  copyContractSLA: function(contractSLAGr) {
  	var copyContractSLAGr = new GlideRecord(this.TABLE_CONTRACT_SLA);

  	if (!contractSLAGr)
  		return copyContractSLAGr;

  	var fieldData = {};
  	this.gru.populateFromGR(fieldData, contractSLAGr);
  	this.gru.mergeToGR(fieldData, copyContractSLAGr);

  	return copyContractSLAGr;
  },

  copyTaskSLA: function(taskSLAGr) {
  	var copyTaskSLAGr = new GlideRecord('task_sla');

  	if (!taskSLAGr || !taskSLAGr.getUniqueValue())
  		return copyTaskSLAGr;

  	var fieldData = {};
  	this.gru.populateFromGR(fieldData, taskSLAGr);
  	this.gru.mergeToGR(fieldData, copyTaskSLAGr);

  	return copyTaskSLAGr;
  },

  isLegacySLACommitmentsActive: function() {
  	var serviceOfferingSLA = GlideTableDescriptor.get(this.TABLE_SERVICE_OFFERING_SLA);
  	return serviceOfferingSLA.isValid() && serviceOfferingSLA.getED().isActive();
  },

  isSLACommitmentsActive: function() {
  	var contractSLA = GlideTableDescriptor.get(this.TABLE_CONTRACT_SLA);
  	return contractSLA.isValid() && contractSLA.isValidField(this.ATTR_SERVICE_COMMITMENT);
  },

  isServiceCommitmentSLA: function(slaGr) {
  	if (!slaGr || !slaGr.getUniqueValue())
  		return false;

  	if (!this.isLegacySLACommitmentsActive() && !this.isSLACommitmentsActive())
  		return false;

  	if (this.isLegacySLACommitmentsActive() && slaGr.getValue('sys_class_name') === 'service_offering_sla')
  		return true;

  	if (this.isSLACommitmentsActive() && '' + slaGr.service_commitment === 'true')
  		return true;

  	return false;
  },

  getHistoryWalker: function(tableName, sysId, recordLevelSecurity, fieldLevelSecurity, withVariables, walkToFirstUpdate, withJournalFields, withSysFields) {
  	if (!tableName || !sysId)
  		return null;

  	var hw;
  	try {
  		var useAudit = false;
  		if (tableName) {
  			var useAuditTableProperty = this.HISTORY_WALKER_USE_AUDIT_PREFIX_PROPERTY + tableName;
  			useAudit = gs.getProperty(useAuditTableProperty, 'false') + '' === 'true';
  		}

  		hw = new sn_hw.HistoryWalker(tableName, sysId, useAudit);
  	} catch (e) {
  		hw = null;
  		if (this._log.atLevel(GSLog.ERR))
  			this._log.logError('getHistoryWalker: Failed to initialise HistoryWalker: ' + e);
  	}

  	if (!hw)
  		return null;

  	//Validate boolean inputs
  	recordLevelSecurity = 'true' === '' + recordLevelSecurity;
  	fieldLevelSecurity = 'true' === '' + fieldLevelSecurity;
  	withVariables = 'true' === '' + withVariables;
  	walkToFirstUpdate = 'true' === '' + walkToFirstUpdate;
  	withJournalFields = "true" === "" + withJournalFields;
  	withSysFields = "true" === "" + withSysFields;

  	hw.setRecordLevelSecurity(recordLevelSecurity);
  	hw.setFieldLevelSecurity(fieldLevelSecurity);
  	hw.setWithVariables(withVariables);
  	hw.setWithJournalFields(withJournalFields);
  	hw.setWithSysFields(withSysFields);

  	if (walkToFirstUpdate && !hw.walkTo(0)) {
  		this._log.logError('getHistoryWalker: Failed to walk to update 0');
  		return null;
  	}

  	return hw;
  },

  getTimezone: function(taskSLAGr) {
  	if (!taskSLAGr)
  		return '';

  	var timezone = '' + taskSLAGr.schedule.time_zone;
  	if (!timezone)
  		timezone = taskSLAGr.getValue('timezone');
  	if (!timezone)
  		timezone = gs.getSysTimeZone();
  	return timezone;
  },

  getSLADurationInMs: function(taskSLAGr, slaDefGr, includePause) {
  	var slaDurationMs = null;
  	if (!taskSLAGr || !taskSLAGr.isValid())
  		return slaDurationMs;

  	if (!slaDefGr || !slaDefGr.isValid())
  		slaDefGr = this.getSLADefFromTaskSLA(taskSLAGr);

  	if (slaDefGr === null)
  		return slaDurationMs;

  	// If it's a user specified duration we can just return that plus pause time if requested
  	if (slaDefGr.duration_type.nil()) {
  		slaDurationMs = slaDefGr.duration.dateNumericValue();
  		if ('' + includePause === 'true')
  			slaDurationMs += taskSLAGr.business_pause_duration.dateNumericValue();

  		return slaDurationMs;
  	}

  	var durationCalculator = this.getDurationCalculatorForTaskSLA(taskSLAGr);
  	if (!this.alwaysRunRelDurScript && taskSLAGr.isValidField('original_breach_time') && !taskSLAGr.original_breach_time.nil())
  		durationCalculator.calcScheduleDuration(null, taskSLAGr.original_breach_time.getGlideObject());
  	else {
  		// Store the current value of the global variable called 'current'
  		var ocurrent = null;
  		if (typeof current !== 'undefined')
  			ocurrent = current;

  		// Set 'current' to point to either the 'task_sla' record or the 'table' record associated with the 'SLA Definition'
  		if (slaDefGr.getValue('relative_duration_works_on') === 'SLA record')
  			current = taskSLAGr;
  		else
  			current = taskSLAGr.task.getRefRecord();

  		// Perform the relative calculation using the revised value of 'current'
  		dc.calcRelativeDuration(slaDefGr.getValue('duration_type'));

  		// Reset 'current' to point back to its original value
  		if (ocurrent)
  			current = ocurrent;
  	}

  	return durationCalculator.getSeconds() * 1000;
  },

  getSLADefFromTaskSLA: function(taskSLAGr) {
  	var slaDefGr = null;
  	if (!taskSLAGr || !taskSLAGr.isValid())
  		return slaDefGr;

  	slaDefGr = new GlideRecord(this.TABLE_CONTRACT_SLA);
  	slaDefGr.addQuery('sys_id', taskSLAGr.getValue('sla'));
  	if (taskSLAGr.isValidField('sys_domain'))
  		slaDefGr.addDomainQuery(taskSLAGr);
  	slaDefGr.query();

  	if (!slaDefGr.next())
  		return null;

  	return slaDefGr;
  },

  getDurationCalculatorForTaskSLA: function(taskSLAGr) {
  	var durationCalculator = new DurationCalculator();
  	if (!taskSLAGr)
  		return durationCalculator;

  	var tz = this.getTimezone(taskSLAGr);
  	if (!taskSLAGr.schedule.nil())
  		durationCalculator.setSchedule(taskSLAGr.getValue('schedule'), tz);
  	durationCalculator.setStartDateTime(this.getGlideDateTimeObject(taskSLAGr.start_time));

  	return durationCalculator;
  },

  getGlideDateTimeObject: function(glide_date_time) {
  	if (!glide_date_time)
  		return new GlideDateTime();
  	if (JSUtil.isJavaObject(glide_date_time) && JSUtil.instance_of(glide_date_time, 'com.glide.glideobject.GlideDateTime'))
  		return glide_date_time;

  	return new GlideDateTime(glide_date_time.getGlideObject());
  },

  refreshTaskSlasByTask: function(taskSysIds) {
  	if (!taskSysIds || !Array.isArray(taskSysIds))
  		return;

  	if (this._log.atLevel(GSLog.DEBUG))
  		this._log.debug('[refreshTaskSlasByTask] taskSysIds: ' + taskSysIds.join(','));

  	// if a Task has unprocessed records in the 'sla_async_queue' then do not call SLACalculatorNG
  	var unqueuedTaskSysIds = taskSysIds.filter(function(taskSysId) {
  		return !new SLAAsyncQueue().isTaskQueued(taskSysId);
  	});

  	if (this._log.atLevel(GSLog.DEBUG))
  		this._log.debug('[refreshTaskSlasByTask] unqueuedTaskSysIds: ' + unqueuedTaskSysIds.join(','));

  	var isTwentyElevenEngine = this._gs.getProperty('com.snc.sla.engine.version', '2010') === '2011';

  	var taskSlaGr = new GlideRecord('task_sla');
  	taskSlaGr.addQuery('task', 'IN', unqueuedTaskSysIds);
  	taskSlaGr.addQuery('stage', '!=', 'paused');
  	taskSlaGr.addActiveQuery();
  	taskSlaGr.query();
  	while (taskSlaGr.next()) {
  		// Disable running of workflow for recalculation of SLA
  		taskSlaGr.setWorkflow(false);
  		isTwentyElevenEngine ? SLACalculatorNG.calculateSLA(taskSlaGr) : new SLACalculator().calcAnSLA(taskSlaGr);
  		taskSlaGr.setWorkflow(true);
  	}
  },

  getScheduleData: function(taskSlaGr) {
  	if (!taskSlaGr || !taskSlaGr.getUniqueValue() || !taskSlaGr.sla)
  		return null;

  	var scheduleSysId = taskSlaGr.getValue('schedule');

  	if (!scheduleSysId)
  		return null;

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_getScheduleData] scheduleSysId: ' + scheduleSysId);

  	var schedule = new GlideSchedule(scheduleSysId);
  	var now = new GlideDateTime();
  	var whenNext = new GlideDateTime();
  	whenNext.add(schedule.whenNext());

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_getScheduleData] now: ' + now.getDisplayValue() + ' whenNext: ' + whenNext.getDisplayValue());

  	var glideScheduleTimeMap = schedule.getTimeMap(now, whenNext, null);

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		glideScheduleTimeMap.dumpTimeMapTZ();

  	var scheduleData = {};
  	scheduleData.timezone = schedule.getTZ().getID();
  	scheduleData.in_schedule = schedule.isInSchedule(now);

  	var scheduleDateTimeSpan = glideScheduleTimeMap.next();

  	if (!scheduleDateTimeSpan) {

  		if (this._log.atLevel(global.GSLog.DEBUG))
  			this._log.debug('[getScheduleData] scheduleData: ' + JSON.stringify(scheduleData));

  		return scheduleData;
  	}

  	scheduleData.actual_start = {
  		value: scheduleDateTimeSpan.getActualStart().getValue(),
  		display_value: scheduleDateTimeSpan.getActualStart().getDisplayValue()
  	};

  	scheduleData.actual_end = {
  		value: scheduleDateTimeSpan.getActualEnd().getValue(),
  		display_value: scheduleDateTimeSpan.getActualEnd().getDisplayValue()
  	};

  	scheduleData.start = {
  		value: scheduleDateTimeSpan.getStart().getValue(),
  		display_value: scheduleDateTimeSpan.getStart().getDisplayValue()
  	};

  	scheduleData.end = {
  		value: scheduleDateTimeSpan.getEnd().getValue(),
  		display_value: scheduleDateTimeSpan.getEnd().getDisplayValue()
  	};

  	if (scheduleData.in_schedule)
  		scheduleData.schedule_changes_millis = this._timeLeftMS(scheduleDateTimeSpan.getActualEnd().getMS());
  	else
  		scheduleData.schedule_changes_millis = this._timeLeftMS(scheduleDateTimeSpan.getActualStart().getMS());

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[getScheduleData] scheduleData: ' + JSON.stringify(scheduleData));

  	return scheduleData;
  },

  // Get all the Condition fields fron contract_sla table
  getSLAConditionFields: function() {
  	var conditionFields = [];
  	var contractSLAFields = sys_meta[this.TABLE_CONTRACT_SLA];
  	if (!contractSLAFields || contractSLAFields.length === 0)
  		return conditionFields;

  	var keys = Object.keys(contractSLAFields);
  	for (var i = 0; i < keys.length; i++) {
  		var conditionField = contractSLAFields[keys[i]];
  		if (conditionField && conditionField["internal_type"] === "conditions")
  			conditionFields.push(conditionField.name);
  	}

  	return conditionFields;
  },

  getSystemFields: function() {
  	return this.WITH_SYSTEM_FIELDS;
  },

  // Returns an array of journal fields for the given table
  getJournalFields: function(tableName) {
  	var journalFields = [];
  	var tableFields = sys_meta[tableName];
  	if (!tableFields || tableFields.length === 0)
  		return journalFields;

  	var keys = Object.keys(tableFields);
  	for (var i = 0; i < keys.length; i++) {
  		var conditionField = tableFields[keys[i]];
  		if (conditionField && (conditionField["internal_type"] === "journal_input" || conditionField["internal_type"] === "journal"))
  			journalFields.push(conditionField.name);
  	}

  	return journalFields;
  },

  // Tests if the given contract_sla uses advanced conditions with journal fields
  hasAdvancedJournalCondition: function(slaDefGr) {
  	var advConditionType = slaDefGr.getValue(this.ADV_CONDITION_TYPE);

  	return !slaDefGr ? false : (
  		this.SLA_ADV_COND_ADV_WITH_JOURNAL === advConditionType ||
  			this.SLA_ADV_COND_ADV_WITH_JOURNAL_AND_SYSTEM === advConditionType
  	);
  },

  // Tests if the given contract_sla uses advanced conditions with system fields
  hasAdvancedSysFieldCondition: function(slaDefGr) {
  	var advConditionType = slaDefGr.getValue(this.ADV_CONDITION_TYPE);

  	return !slaDefGr ? false : (
  		this.SLA_ADV_COND_ADV_WITH_SYSTEM === advConditionType ||
  			this.SLA_ADV_COND_ADV_WITH_JOURNAL_AND_SYSTEM === advConditionType
  	);
  },

  // Tests if the given contract_sla uses variables in any condition
  hasVariablesCondition: function(slaDefGr) {
  	if (!slaDefGr)
  		return false;

  	var conditionFields = this.getSLAConditionFields();
  	for (var i = 0; i < conditionFields.length; i++) {
  		var conditionField = conditionFields[i];
  		var conditionValue = slaDefGr[conditionField].getValue();

  		if (this.skipConditionCheck(conditionField, conditionValue, slaDefGr))
  			continue;

  		var qs = new GlideQueryString(conditionValue);
  		qs.deserialize();
  		var terms = qs.getTerms();
  		for (var j = 0; j < terms.size(); j++) {
  			var field = terms.get(j).getField();
  			var operator = terms.get(j).getOperator() + '';

  			// Catch variables or catalog task variable term
  			if (field && (field.startsWith("variables.") ||
  				(field.startsWith("variables") &&
  					(operator === "HASITEMVARIABLE" || operator === "HASQUESTION" || operator === "HASVARIABLE"))))
  				return true;
  		}
  	}

  	return false;
  },

  skipConditionCheck: function(conditionField, conditionValue, slaDefGr) {
  	if (!conditionValue || !slaDefGr)
  		return true;

  	if (conditionField === this.CANCEL_CONDITION && !slaDefGr.getValue(this.WHEN_TO_CANCEL) === this.ON_CONDITION)
  		return true;

  	if (conditionField === this.RESUME_CONDITION && !slaDefGr.getValue(this.WHEN_TO_RESUME) === this.ON_CONDITION)
  		return true;

  	return false;
  },

  getNoAuditFields: function(tableName) {
  	var fields = {};
  	if (!GlideTableDescriptor.isValid(tableName))
  		return fields;

  	var gr = new GlideRecord(tableName);
  	var elements = gr.getElements();

  	for (var i = 0; i < elements.size(); i++) {
  		var element = elements.get(i);
  		var elementName = element.getName();

  		if (this.IGNORE_UNAUDITED && this.IGNORE_UNAUDITED[elementName] === true)
  			continue;

  		var elementDescriptor = element.getED();
  		if (!elementDescriptor)
  			continue;

  		var noAuditValue = "" + elementDescriptor.getBooleanAttribute("no_audit", false);
  		if (noAuditValue !== "true")
  			continue;

  		var fieldMeta = gr[elementName].sys_meta;
  		fields[elementName] = { label: fieldMeta.label, attributes: fieldMeta.attributes };
  	}

  	return fields;
  },

  getSLAUpdateSourceEngineParameter: function(taskSLAGr) {
  	return this.getTaskSLAEngineParameter(taskSLAGr, this.SLA_UPDATE_SOURCE_ENGINE_PARAMETER);
  },

  getTaskSLAEngineParameter: function(taskSLAGr, paramName) {
  	if (!this.isTaskSLARecord(taskSLAGr))
  		return null;

  	return taskSLAGr.getEngineParameter(paramName);
  },

  setSLAUpdateSourceEngineParameter: function(taskSLAGr, paramValue) {
  	this.setTaskSLAEngineParameter(taskSLAGr, this.SLA_UPDATE_SOURCE_ENGINE_PARAMETER, paramValue);
  },

  setTaskSLAEngineParameter: function(taskSLAGr, paramName, paramValue) {
  	if (!this.isTaskSLARecord(taskSLAGr)) {
  		if (this._log.atLevel(global.GSLog.DEBUG))
  			this._log.debug('setTaskSLAEngineParameter: taskSLAGr is not a "task_sla" GlideRecord object, taskSLAGr=' + (taskSLAGr === null ? "null" : taskSLAGr));
  		return;
  	}

  	if (gs.nil(paramName)) {
  		if (this._log.atLevel(global.GSLog.DEBUG))
  			this._log.debug('setTaskSLAEngineParameter: no parameter name supplied');
  		return;
  	}

  	if (gs.nil(paramValue)) {
  		if (this._log.atLevel(global.GSLog.DEBUG))
  			this._log.debug('setTaskSLAEngineParameter: no parameter value supplied');
  		paramValue = "";
  	}

  	taskSLAGr.setEngineParameter(paramName, paramValue);
  },

  isTaskSLARecord: function(taskSLAGr) {
  	return taskSLAGr && taskSLAGr instanceof GlideRecord && taskSLAGr.getRecordClassName() === "task_sla";
  },

  _timeLeftMS: function(nextTimeMS) {
  	if (!nextTimeMS)
  		return 0;

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_timeLeftMS] nextTimeMS: ' + nextTimeMS);

  	var nowGDT = new GlideDateTime();
  	var nowMS = nowGDT.getNumericValue();
  	var timeLeftMS = nextTimeMS - nowMS;

  	if (this._log.atLevel(global.GSLog.DEBUG))
  		this._log.debug('[_timeLeftMS] timeLeftMS: ' + timeLeftMS);

  	return timeLeftMS;
  },

  type: 'SLAUtilSNC'
};

Sys ID

1a9fdd9b9f6322002920bde8132e70e1

Offical Documentation

Official Docs: