Name
global.STTRMModelSNC
Description
ServicenNow code for the STTRMModel class
Script
var STTRMModelSNC = Class.create();
STTRMModelSNC.prototype = {
CACHE_NAME: 'com.snc.itsm.state_transition_model',
READ_ROLES: 'read_roles',
WRITE_ROLES: 'write_roles',
TABLES: {
hide: 'sttrm_model_user_criteria_hide_mtom',
read_roles: 'sttrm_model_user_criteria_read_mtom',
write_roles: 'sttrm_model_user_criteria_write_mtom'
},
LOG_PROPERTY: "com.snc.itsm.state_transition_model.log",
initialize: function(stateTransitionModelGr, _gs) {
this._gr = stateTransitionModelGr;
this._gs = _gs || gs;
this._log = new GSLog(this.LOG_PROPERTY, this.type).setLog4J();
this._cached = null;
this._idChk = null;
},
// Caching method, used internally
_initCache: function() {
if (GlideCacheManager.get(this.CACHE_NAME, "_created_") !== null)
return;
GlideCacheManager.addPrivateCacheable(this.CACHE_NAME);
GlideCacheManager.put(this.CACHE_NAME, "_created_", new GlideDateTime().getNumericValue());
},
// Caching method, used internally
_getCached: function() {
if (!this._gr || !this._gr.isValidRecord())
return this._memo();
if (this._cached !== null && this._idChk === this._gr.getUniqueValue())
return this._cached;
this._idChk = this._gr.getUniqueValue();
this._cached = GlideCacheManager.get(this.CACHE_NAME, this._gr.getUniqueValue());
if (this._cached) {
this._cached = JSON.parse(this._cached);
}
else {
this._initCache();
this._cached = this._memo();
this._refreshCache();
}
return this._cached;
},
// Caching method, used internally
_memo: function() {
var memo = {
"initial_state": null,
"states": null,
"terminal_states": null
};
if (!this._gr || !this._gr.isValidRecord())
return memo;
var initialStateGr = this.getInitialState();
if (initialStateGr)
memo.initial_state = initialStateGr.getValue("state_value");
var stateGr = this.getStates();
if (stateGr.hasNext())
memo.states = [];
while (stateGr.next())
memo.states.push(stateGr.getValue("state_value"));
var terminalStateGr = this.getTerminalStates();
if (terminalStateGr.hasNext())
memo.terminal_states = [];
while (terminalStateGr.next())
memo.terminal_states.push(terminalStateGr.getValue("state_value"));
return memo;
},
// Caching method, used internally
_refreshCache: function() {
if (!this._gr || !this._gr.isValidRecord())
return;
GlideCacheManager.put(this.CACHE_NAME, this._gr.getUniqueValue(), JSON.stringify(this._getCached()));
},
// Allow extensions and tools using the sttr models to augment the cache
addToCache: function(key, value) {
this._getCached()[key] = value;
this._refreshCache();
},
// Returns a value from the cache or null
getFromCache: function(key) {
return this._getCached()[key] || null;
},
// Methods for using models
// Applies the initial state for the model
// * processGr: The gr to evaluate the transition to the initial state on
// * modelChanged: True if you are switching between models and don't want to evaluate the transition
applyInitialState: function(processGr, modelChanged) {
var initialStateGr = this.getInitialState();
if (initialStateGr === null || !this._validProcessTable(processGr))
return false;
// If it's not new, go through the usual checks
if (processGr.isNewRecord() || modelChanged) {
processGr.setValue(this.getStateFieldName(), initialStateGr.getValue("state_value"));
return true;
}
return this.applyState(processGr, initialStateGr);
},
// Apply a state value to the processGr for this model
// Returns false if the state cannot be applied
applyState: function(processGr, state) {
var stateGr = this.getState(state);
if (stateGr === null || !this._validProcessTable(processGr))
return false;
if (this.canTransition(processGr, stateGr)) {
processGr.setValue(this.getStateFieldName(), stateGr.getValue("state_value"));
return true;
}
return false;
},
// Evaluates the automated transitions for a process record and sets state if applicable
// Returns true if a state transition was applied, false otherwise
applyAutomaticTransition: function(processGr) {
var stateGr = this.getState(processGr);
if (!stateGr)
return false;
var state = new STTRMState(stateGr);
var transitionGr = state.getAutomaticTransitions();
while (transitionGr.next()) {
var evaluated = new STTRMTransition(transitionGr).evaluateConditions(processGr);
if (evaluated.transition_available) {
processGr.setValue(this.getStateFieldName(), evaluated.to_state);
return true;
}
}
return false;
},
// Gets the name of the field being used to store state
getStateFieldName: function() {
return this._gr.getValue("state_field");
},
// Returns all states for the model
getStates: function() {
var statesGr = new GlideRecord("sttrm_state");
statesGr.addQuery("sttrm_model", this._gr.getUniqueValue());
statesGr.orderBy("state_sequence");
statesGr.query();
return statesGr;
},
// Convenience method to return an array of the states values
getStatesValues: function() {
return this.getFromCache("states");
},
// Returns the sttrm_state GlideRecord or null for a given state value or process record
getState: function(processGrOrStateValue) {
if (!processGrOrStateValue)
return null;
var stateValue = processGrOrStateValue;
if (this._isGlideRecord(processGrOrStateValue)) {
if (processGrOrStateValue.getTableName() === "sttrm_state") {
// Check if it's a valid record and if it's a state record from this model
if (processGrOrStateValue.isValidRecord() && processGrOrStateValue.getValue("sttrm_model") === this._gr.getUniqueValue())
return processGrOrStateValue;
return null;
}
if (!this._validProcessTable(processGrOrStateValue))
return null;
stateValue = processGrOrStateValue.getValue(this.getStateFieldName());
}
var stateGr = new GlideRecord("sttrm_state");
stateGr.addQuery("sttrm_model", this._gr.getUniqueValue());
stateGr.addQuery("state_value", stateValue);
stateGr.query();
if (!stateGr.next())
return null;
return stateGr;
},
// Convenience method to get the value of a state. Uses the cached version of the model
getStateValue: function(processGrOrStateValue) {
if (!processGrOrStateValue)
return null;
var stateValue = processGrOrStateValue;
// Cater for cases where a GlideRecord is passed in
if (this._isGlideRecord(processGrOrStateValue)) {
if (processGrOrStateValue.getTableName() === "sttrm_state") {
// Check if it's a valid record and if it's a state record from this model
if (processGrOrStateValue.isValidRecord() && processGrOrStateValue.getValue("sttrm_model") === this._gr.getUniqueValue())
return processGrOrStateValue.getValue("state_value");
return null;
}
if (!this._validProcessTable(processGrOrStateValue))
return null;
//Even though this is a valid process table we need to check if the state exists in the model
stateValue = processGrOrStateValue.getValue(this.getStateFieldName());
}
if (this.getFromCache("states").indexOf(stateValue) !== -1)
return stateValue;
return null;
},
// Returns the possible transition states for the state of provided processGr or state value
getTransitionStates: function(processGrOrStateValue) {
var currentStateGr = this.getState(processGrOrStateValue);
if (!currentStateGr) {
if (this.log.atLevel(GSLog.DEBUG))
this.log.debug("[getTransitionStates] GlideRecord " + this._gr.getDisplayValue() + "[" +
this._gr.getTableName() + ":" + this._gr.getUniqueValue() +
"] is not in a valid state for this model [" + this._gr.getValue("state") + "]");
return null;
}
return new STTRMState(currentStateGr).getTransitionStates();
},
// Convenience method to get the transion state values. uses the cached version of the model
getTransitionStatesValues: function(processGrOrStateValue) {
if (!processGrOrStateValue)
return null;
var cachedTransitionStates = this.getFromCache("transition_states");
var stateValue = this.getStateValue(processGrOrStateValue);
if (cachedTransitionStates && cachedTransitionStates[stateValue])
return cachedTransitionStates[stateValue];
var transitionStateGr = this.getTransitionStates(processGrOrStateValue);
var transitionStates = [];
while (transitionStateGr && transitionStateGr.next()) {
transitionStates.push(transitionStateGr.getValue("state_value"));
}
var allTransitionStates = cachedTransitionStates || {};
allTransitionStates[stateValue] = transitionStates;
this.addToCache("transition_states", allTransitionStates);
return transitionStates;
},
// Returns the manual transition states for the provided the state or processGr
getManualTransitionStates: function(processGrOrStateValue) {
var currentStateGr = this.getState(processGrOrStateValue);
if (!currentStateGr) {
if (this.log.atLevel(GSLog.DEBUG))
this.log.debug("[getManualTransitionStates] GlideRecord " + this._gr.getDisplayValue() + "[" +
this._gr.getTableName() + ":" + this._gr.getUniqueValue() +
"] is not in a valid state for this model [" + this._gr.getValue("state") + "]");
return null;
}
return new STTRMState(currentStateGr).getManualTransitionStates();
},
/* Returns true if the model allows transition between the process GlideRecord's current state
* and the to state.
*
* At least one process gliderecord has to be provided (from takes precident). 'to' can be a
* second process GR, a state GR from the model or a state value.
*/
canTransition: function(fromProcessGrOrState, toProcessGrOrState) {
var transitionResult = this.evaluateTransition(fromProcessGrOrState, toProcessGrOrState);
return transitionResult.transition_available;
},
/* Evaluates the transition between the process GlideRecord's current state and the to state.
* Returns a minimum of the following:
* {
* transition_available: false,
* // And if valid from and two states are provided
* from_state: "fromStateValue",
* to_state: "toStateValue"
* }
*
* If a valid transition is found:
* {
* sys_id: "sys_id of the transition",
* display_value: "Display Value for the transition",
* from_state: "fromStateValue",
* to_state: "toStateValue"
* transition_available: true/false,
* conditions: [
* {
* passed: true/false,
* condition: {
* "name": "Name given to the condition",
* "description": "Description of the condition",
* "sys_id": "sys_id of the condition"
* }
* }
* ...
* ]
* }
*
* At least one process gliderecord has to be provided ('from' takes precident). 'to' can be a
* second process GR, an sttrm_state GR from the model or a state value.
*/
evaluateTransition: function(fromProcessGrOrState, toProcessGrOrState) {
var transitionResult = {
transition_available: false
};
var evaluationGr = null;
if (this._isGlideRecord(fromProcessGrOrState) && this._validProcessTable(fromProcessGrOrState))
evaluationGr = fromProcessGrOrState;
else if (this._isGlideRecord(toProcessGrOrState) && this._validProcessTable(toProcessGrOrState))
evaluationGr = toProcessGrOrState;
if (evaluationGr === null)
return transitionResult;
var fromState = this.getState(fromProcessGrOrState);
if (!fromState)
return transitionResult;
var toState = this.getState(toProcessGrOrState);
if (!toState)
return transitionResult;
transitionResult.from_state = fromState.getValue("state_value");
transitionResult.to_state = toState.getValue("state_value");
var transitionGr = new STTRMState(fromState).getTransition(toState);
if (!transitionGr)
return transitionResult;
while (transitionGr.next()) {
transitionResult = new STTRMTransition(transitionGr).evaluateConditions(evaluationGr);
if (transitionResult.transition_available)
break;
}
if (this._log.atLevel(global.GSLog.DEBUG))
this._log.debug("[evaluateTransition] Evaluated transition:\n" + JSON.stringify(transitionResult, null, 3));
return transitionResult;
},
//Returns an sttrm_state GlideRecord for initial state of a model or null
getInitialState: function() {
var stateGr = new GlideRecord("sttrm_state");
stateGr.addQuery("sttrm_model", this._gr.getUniqueValue());
stateGr.addQuery("initial_state", true);
stateGr.orderBy("state_sequence");
stateGr.setLimit(1);
stateGr.query();
if (stateGr.next())
return stateGr;
// If there is no initial set, return the first in the sequence of added states
stateGr = new GlideRecord("sttrm_state");
stateGr.addQuery("sttrm_model", this._gr.getUniqueValue());
stateGr.orderBy("state_sequence");
stateGr.setLimit(1);
stateGr.query();
if (stateGr.next())
return stateGr;
// If there are no records, return null
return null;
},
// Convenience method to get the intial state value. Uses cache
getInitialStateValue: function() {
return this.getFromCache("initial_state");
},
// Returns a sttrm_state GlideRecord containing all terminal states (no transitions)
getTerminalStates: function() {
var stateTransitionGr = new GlideRecord("sttrm_state_transition");
stateTransitionGr.addQuery("from_state.sttrm_model", this._gr.getUniqueValue());
stateTransitionGr.query();
var stateSysIds = [];
while (stateTransitionGr.next())
stateSysIds.push(stateTransitionGr.getValue("from_state"));
var stateGr = new GlideRecord("sttrm_state");
stateGr.addQuery("sttrm_model", this._gr.getUniqueValue());
stateGr.addQuery("sys_id", "NOT IN", stateSysIds.join(","));
stateGr.orderBy("state_sequence");
stateGr.query();
return stateGr;
},
// Convenience method to get terminal state values. Uses cache
getTerminalStatesValues: function() {
return this.getFromCache("terminal_states");
},
// Returns true if the processGr is in a terminal state
inTerminalState: function(processGrOrState) {
var cached = this._getCached();
if (Array.isArray(cached.terminal_states)) {
var stateValue = processGrOrState;
if (this._isGlideRecord(processGrOrState))
stateValue = processGrOrState.getTableName() === "sttrm_state" ?
processGrOrState.getValue("state_value") : processGrOrState.getValue(this.getStateFieldName());
return cached.terminal_states.indexOf(stateValue + "") !== -1;
}
// If there's no caching then use DB
var stateGr = this.getState(processGrOrState);
if (stateGr === null)
return false;
var terminalStateGr = this.getTerminalStates();
while (terminalStateGr.next())
if (terminalStateGr.getUniqueValue() === stateGr.getUniqueValue())
return true;
return false;
},
// Returns true if the processGr is in the initial state
inInitialState: function(processGrOrState) {
var cached = this._getCached();
if (cached.initial_state !== null) {
var stateValue = processGrOrState;
if (this._isGlideRecord(processGrOrState))
stateValue = processGrOrState.getTableName() === "sttrm_state" ?
processGrOrState.getValue("state_value") : processGrOrState.getValue(this.getStateFieldName());
return cached.initial_state === stateValue + "";
}
// If there's no caching use DB
var stateGr = this.getState(processGrOrState);
if (stateGr === null)
return false;
return this.getInitialState().getUniqueValue() === stateGr.getUniqueValue();
},
// Methods for building models
// Returns the states which are available to use in the model.
getAvailableStateChoices: function(selectedChoice) {
var choices = this._getSysChoices();
var existingStateGr = this.getStates();
while (existingStateGr.next()) {
if (existingStateGr.getValue("state_value") === selectedChoice)
continue;
choices.some(function(choice, idx) {
if (choice.value === existingStateGr.getValue("state_value")) {
choices.splice(idx, 1);
return true;
}
});
}
return choices;
},
hasAvailableStates: function() {
return this.getAvailableStateChoices().length > 0;
},
insertWithStates: function() {
var targetModelSysId = this._copyModel();
this._copyStates(targetModelSysId);
return targetModelSysId;
},
evaluateReadSecurity: function() {
// If a user has write access then the they are automatically give read access
var canWrite = this.evaluateWriteSecurity();
if (canWrite)
return canWrite;
var canRead = this._evaluateSecurity(this.READ_ROLES);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[evaluateReadSecurity] canRead: ' + canRead);
return canRead;
},
evaluateWriteSecurity: function() {
var canWrite = this._evaluateSecurity(this.WRITE_ROLES);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[evaluateWriteSecurity] canWrite: ' + canWrite);
return canWrite;
},
_evaluateSecurity: function(access) {
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateSecurity] access: ' + access + ' for: ' + this._gr.getDisplayValue());
if (!(access === this.READ_ROLES || access === this.WRITE_ROLES))
return false;
var user = this._gs.getUser();
var roles = this._gr[access].getValue() + '';
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateSecurity] access: ' + access + ' roles: ' + roles);
var tableName = this._gr.getValue('table_name');
if (!tableName)
return false;
var relatedTableGr = new GlideRecord(tableName);
var canReadRelatedTable = relatedTableGr.canRead();
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateSecurity] tableName: ' + tableName + ' canReadRelatedTable: ' + canReadRelatedTable);
if (!canReadRelatedTable)
return false;
if (roles && !this._gr[access].nil() && user.hasRole(roles))
return true;
var hasAdvancedSecurity = this._gr.getValue('advanced_security') + '' === '1';
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateSecurity] hasAdvancedSecurity: ' + hasAdvancedSecurity);
if (!hasAdvancedSecurity)
return false;
return this._evaluateUserCriteria(access, user.getID());
},
_evaluateUserCriteria: function(access, userSysId) {
if (!(access === this.READ_ROLES || access === this.WRITE_ROLES))
return false;
if (!userSysId)
return false;
var sttrmModelSysId = this._gr.getUniqueValue();
if (!sttrmModelSysId)
return false;
if (typeof sn_uc === 'undefined' || typeof sn_uc.UserCriteriaLoader === 'undefined')
return false;
var hideUserCriteriaSysIds = this._getUserCriteriaByMtom(this.TABLES.hide, sttrmModelSysId);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateUserCriteria] hideUserCriteriaSysIds: ' + hideUserCriteriaSysIds);
var userBlocked = sn_uc.UserCriteriaLoader.userMatches(userSysId, hideUserCriteriaSysIds);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateUserCriteria] userBlocked: ' + userBlocked);
// The Not Available For settings override Available For settings. A user on the Not Available For cannot access
// that model, even if that user is also on the Available For list for that model.
if (userBlocked)
return false;
var accessTable = this.TABLES[access];
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateUserCriteria] accessTable: ' + accessTable + ' userSysId: ' + userSysId + ' sttrmModelSysId: ' + sttrmModelSysId);
var userCriteriaSysIds = this._getUserCriteriaByMtom(accessTable, sttrmModelSysId);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateUserCriteria] userCriteriaSysIds: ' + userCriteriaSysIds);
var userHasAccess = sn_uc.UserCriteriaLoader.userMatches(userSysId, userCriteriaSysIds);
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug('[_evaluateUserCriteria] userHasAccess: ' + userHasAccess);
return userHasAccess;
},
_getUserCriteriaByMtom: function(accessTable, sttrmModelSysId) {
var userCriteriaSysIds = this.getFromCache(accessTable);
if (!Array.isArray(userCriteriaSysIds)) {
userCriteriaSysIds = [];
var gr = new GlideRecord(accessTable);
gr.addActiveQuery();
gr.addQuery('sttrm_model', sttrmModelSysId);
gr.addNotNullQuery('user_criteria');
gr.query();
while (gr.next())
userCriteriaSysIds.push(gr.getValue('user_criteria') + '');
this.addToCache(accessTable, userCriteriaSysIds);
}
return userCriteriaSysIds;
},
copy: function() {
var targetModelSysId = this._copyModel();
var mappedStates = this._copyStates(targetModelSysId);
var mappedTransitions = this._copyTransitions(mappedStates);
this._copyTransitionConditions(mappedTransitions);
return targetModelSysId;
},
_copyModel: function() {
var fields = ChangeCommon.toJS(this._gr);
var name = fields.name.value;
var tableName = fields.sys_class_name.value;
var gr = new GlideRecord(tableName);
gr.initialize();
for (var i = 0; i < Object.keys(fields).length; i++) {
var fieldName = Object.keys(fields)[i];
var value = fields[fieldName].value;
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug("[_createNewModel] Copying field: " + fieldName + " - value: " + value);
gr.setValue(fieldName, value);
}
gr.setValue("name", gs.getMessage("{0} (copy)", name));
gr.setValue("active", "false");
return gr.insert();
},
_copyStates: function(newModelSysId) {
var states = [];
if (this._gr && this._gr.isValidRecord() && newModelSysId) {
var statesGr = this.getStates();
var gr = new GlideRecord("sttrm_state");
while (statesGr.next()) {
gr.initialize();
gr.setValue("sttrm_model", newModelSysId);
gr.setValue("state_value", statesGr.getValue("state_value"));
gr.setValue("state_label", statesGr.getValue("state_label"));
gr.setValue("state_sequence", statesGr.getValue("state_sequence"));
gr.setValue("initial_state", statesGr.getValue("initial_state"));
states[statesGr.getUniqueValue()] = gr.insert();
}
}
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug("[_copyStates] States: " + JSON.stringify(states));
return states;
},
_copyTransitions: function(mappedStates) {
var transitions = {};
var sourceTransitionsGr = this._getAllStateTransitionsGr();
while (sourceTransitionsGr.next()) {
var targetGr = new GlideRecord("sttrm_state_transition");
targetGr.initialize();
targetGr.setValue("automatic", sourceTransitionsGr.getValue("automatic"));
targetGr.setValue("from_state", mappedStates[sourceTransitionsGr.getValue("from_state")]);
targetGr.setValue("to_state", mappedStates[sourceTransitionsGr.getValue("to_state")]);
transitions[sourceTransitionsGr.getUniqueValue()] = targetGr.insert();
}
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug("[_copyTransitions] target transitions: " + JSON.stringify(transitions));
return transitions;
},
_copyTransitionConditions: function(mappedTransitions /** Array of transition condition objects to copy **/ ) {
if (this._log.atLevel(GSLog.DEBUG))
this._log.debug("[_copyTransitionConditions] conditions: " + JSON.stringify(mappedTransitions));
var sourceConditionsGr = this._getTransitionConditionsGr(Object.keys(mappedTransitions));
var conditionGr = new GlideRecord("sttrm_transition_condition");
while (sourceConditionsGr.next()) {
conditionGr.initialize();
var targetTransition = mappedTransitions[sourceConditionsGr.getValue("sttrm_state_transition")];
conditionGr.setValue("sttrm_state_transition", targetTransition);
conditionGr.setValue("condition_type", sourceConditionsGr.getValue("condition_type"));
conditionGr.setValue("condition_script", sourceConditionsGr.getValue("condition_script"));
conditionGr.setValue("description", sourceConditionsGr.getValue("description"));
conditionGr.setValue("condition", sourceConditionsGr.getValue("condition"));
conditionGr.setValue("name", sourceConditionsGr.getValue("name"));
conditionGr.setValue("order", sourceConditionsGr.getValue("order"));
conditionGr.insert();
}
},
_getAllStateTransitionsGr: function() {
var gr = new GlideRecord("sttrm_state_transition");
gr.addQuery("from_state.sttrm_model", this._gr.getUniqueValue());
gr.query();
return gr;
},
_getTransitionConditionsGr: function(transitionsSysIds /** Array of transitions sys_ids */ ) {
var gr = new GlideRecord("sttrm_transition_condition");
gr.addQuery("sttrm_state_transition", "IN", transitionsSysIds);
gr.query();
return gr;
},
_validProcessTable: function(processGr) {
if (this._gr.getValue("table_name") === processGr.getTableName())
return true;
return false;
},
_isGlideRecord: function(inputVar) {
return inputVar && typeof inputVar.getTableName === "function";
},
//Returns the SysChoices for the given table and field
_getSysChoices: function() {
var retVal = [];
var choiceGr = new GlideSysChoice(
this._gr.getValue("table_name"),
this._gr.getValue("state_field")
).getChoices();
while (choiceGr.next()) {
if (choiceGr.getValue("inactive") === "1")
continue;
retVal.push({
"value": choiceGr.getValue("value"),
"label": choiceGr.getDisplayValue("label"),
"sequence": choiceGr.getValue("sequence")
});
}
return retVal;
},
type: 'STTRMModelSNC'
};
// Choice Script for the state_field
// Returns a ChoiceList of field names which are Choice Lists on the table provided
STTRMModelSNC.getStateFieldChoices = function(tableName) {
if (!tableName)
return null;
var processTableGr = new GlideRecord(tableName);
if (!processTableGr.isValid())
return null;
processTableGr.initialize();
var fields = processTableGr.getFields();
var fieldChoices = new GlideChoiceList();
for (var i = 0; i < fields.size(); i++) {
var field = fields.get(i);
if (field.getED().isChoiceTable())
fieldChoices.add(field.getName() + "", field.getLabel() + " ["+ field.getName() + "]");
}
return fieldChoices;
};
STTRMModelSNC.clearCache = function() {
GlideCacheManager.flush(STTRMModelSNC.prototype.CACHE_NAME);
};
Sys ID
850ec1b95372101034d1ddeeff7b121d