Name
sn_risk_advanced.RiskAssessmentScoringUtilsBase
Description
Utility function for risk assessment scoring(Not for customizations)
Script
var RiskAssessmentScoringUtilsBase = Class.create();
RiskAssessmentScoringUtilsBase.prototype = {
initialize: function() {},
autoCalculateResidualAssessment: function(asmt) {
return this._autoCalculateResidualAssessment(asmt);
},
copyScoreToAssessmentSummaryFieldsForControl: function(asmt) {
this._copyScoreToAssessmentSummaryFieldsForControl(asmt);
},
copyScoreToAssessmentSummaryFieldsForInherent: function(asmt) {
this._copyScoreToAssessmentSummaryFieldsForInherent(asmt);
},
copyScoreToAssessmentSummaryFieldsForResidual: function(asmt) {
this._copyScoreToAssessmentSummaryFieldsForResidual(asmt);
},
copyScoreToAssessmentSummaryFieldsForTarget: function(asmt) {
this._copyScoreToAssessmentSummaryFieldsForTarget(asmt);
},
getRatingScore: function(asmtType, score) {
return this._getRatingScore(asmtType, score);
},
shouldConsiderControlWeightage: function(ramId) {
return this._shouldConsiderControlWeightage(ramId);
},
// The assessment instance scores and ales shall be calculated using logic/script only if there are no corresponding root responses which are mandatory and the required fields are not filled
_checkIfAsmtInstanceScoreNeedsToBeCalculated: function(asmt_instance_id, asmt_type, asmtTypeContri) {
var count = 0;
var rootResponses = new GlideAggregate('sn_risk_advanced_risk_assessment_instance_response');
rootResponses.addAggregate('COUNT');
rootResponses.addNullQuery('parent_instance_response');
rootResponses.addQuery('assessment_instance_id', asmt_instance_id);
rootResponses.addQuery('assessment_type', asmt_type);
rootResponses.addQuery('factor.mandatory_response', true);
if (asmtTypeContri == '1' || asmtTypeContri == '2') {
if (asmtTypeContri == '1') {
// If assessment type contribution is Quantitative, if any mandatory root response(Quantitative/Both) has quantitative response empty?
rootResponses.addEncodedQuery('quantitative_responseISEMPTY^factor.factor_contributionIN1,3');
} else {
// If assessment type contribution is Qualitative, if any mandatory root response(Qualitative/Both) has qualitative response empty?
rootResponses.addEncodedQuery('qualitative_responseISEMPTY^factor.factor_contributionIN2,3');
}
rootResponses.setGroup(false);
rootResponses.query();
if (rootResponses.next()) {
count = parseInt(rootResponses.getAggregate('COUNT'));
}
} else {
// If assessment type contribution is BOTH, if any mandatory root response(BOTH/Qual/Quant) has qualitative or quantitative response empty?
rootResponses.addEncodedQuery('qualitative_responseISEMPTY^factor.factor_contributionIN2,3');
rootResponses.setGroup(false);
rootResponses.query();
if (rootResponses.next()) {
count = parseInt(rootResponses.getAggregate('COUNT'));
}
if (count == 0) {
var responses = new GlideAggregate('sn_risk_advanced_risk_assessment_instance_response');
responses.addAggregate('COUNT');
responses.addNullQuery('parent_instance_response');
responses.addQuery('assessment_instance_id', asmt_instance_id);
responses.addQuery('assessment_type', asmt_type);
responses.addQuery('factor.mandatory_response', true);
responses.addEncodedQuery('quantitative_responseISEMPTY^factor.factor_contributionIN1,3');
responses.setGroup(false);
responses.query();
if (responses.next()) {
count = parseInt(responses.getAggregate('COUNT'));
}
}
}
return (count == 0);
},
// To get scoring logic, script and contribution for asmt type corresponding to the root response
_getAssessmentTypeContribution: function(risk_asmt_meth_id, asmtTypeClass, asmtTypeObject) {
var asmtTypeRec = new GlideRecord('sn_risk_advanced_assessment_type');
asmtTypeRec.addQuery('risk_assessment_methodology', risk_asmt_meth_id);
asmtTypeRec.addQuery('sys_class_name', asmtTypeClass);
asmtTypeRec.query();
if (asmtTypeRec.next()) {
asmtTypeObject.contribution = asmtTypeRec.assessment_contribution + '';
asmtTypeObject.quantitative_scoring_logic = asmtTypeRec.quantitative_scoring_logic + '';
asmtTypeObject.qualitative_scoring_logic = asmtTypeRec.qualitative_scoring_logic + '';
asmtTypeObject.id = asmtTypeRec.getUniqueValue();
}
},
// To calculate and set Assessment instance scores when Root responses are set
calculateAssessmentInstanceScores: function(asmtResponse) {
return this._calculateAssessmentInstanceScores(asmtResponse);
},
_calculateAssessmentInstanceScores: function(asmtResponse) {
var asmt_instance_id = asmtResponse.assessment_instance_id + '';
var risk_asmt_meth_id = asmtResponse.assessment_instance_id.risk_assessment_methodology + '';
var asmt_type = asmtResponse.assessment_type + '';
var assessmentTypeClassName;
var scoreFieldToSet;
var ratingFieldToSet;
var aleFieldToSet;
// This object will contain the logic, scripts and contribution for asmt type
var asmtTypeObject = {};
// IF asmt type for response is inherent, calculate inherent scores
if (asmtResponse.assessment_type == '1') {
assessmentTypeClassName = 'sn_risk_advanced_inherent_assessment';
aleFieldToSet = 'inherent_computed_ale';
scoreFieldToSet = 'inherent_computed_score';
ratingFieldToSet = 'inherent_computed_risk';
} else if (asmtResponse.assessment_type == '2') {
// If asmt type for response is control, calculate control scores
assessmentTypeClassName = 'sn_risk_advanced_control_assessment';
ratingFieldToSet = 'control_computed_effectiveness';
scoreFieldToSet = 'control_computed_score';
} else if (asmtResponse.assessment_type == '3') {
// If asmt type for response is residual, calculate residual scores
assessmentTypeClassName = 'sn_risk_advanced_residual_assessment';
aleFieldToSet = 'residual_computed_ale';
ratingFieldToSet = 'residual_computed_risk';
scoreFieldToSet = 'residual_computed_score';
} else if (asmtResponse.assessment_type == '4') {
// If asmt type for response is target, calculate residual scores
assessmentTypeClassName = 'sn_risk_advanced_target_assessment';
aleFieldToSet = 'target_computed_ale';
ratingFieldToSet = 'target_computed_risk';
scoreFieldToSet = 'target_computed_score';
}
// Get Scoring logics, scripts and assessment contribution for Assessment type
this._getAssessmentTypeContribution(risk_asmt_meth_id, assessmentTypeClassName, asmtTypeObject);
var asmtInstance = new GlideRecord('sn_risk_advanced_risk_assessment_instance');
asmtInstance.get(asmt_instance_id);
if (this._checkIfAsmtInstanceScoreNeedsToBeCalculated(asmt_instance_id, asmt_type, asmtTypeObject.contribution)) {
if (asmtTypeObject.contribution == '3' || asmtTypeObject.contribution == '2') {
// If asmt type has contri of BOTH/Qual, get score
var qualitative_scoring_formula = asmtTypeObject.qualitative_scoring_logic;
var qualitative_score = this._getAsmtTypeScore(qualitative_scoring_formula, 'qualitative_response', asmt_instance_id, asmt_type, '2', asmtTypeObject.id);
// Get rating from score
var rating = this._getRatingScore(asmtTypeObject.id, qualitative_score);
// Set corresponding score field in instance
if (asmtInstance.getValue(ratingFieldToSet) === null && rating != '') {
asmtInstance.setValue(ratingFieldToSet, rating);
} else if (asmtInstance.getValue(ratingFieldToSet) !== null && rating == '') {
asmtInstance.setValue(ratingFieldToSet, rating);
} else if (asmtInstance.getValue(ratingFieldToSet) != rating) {
asmtInstance.setValue(ratingFieldToSet, rating);
}
if (asmtInstance.getValue(scoreFieldToSet) === null && qualitative_score != '') {
asmtInstance.setValue(scoreFieldToSet, qualitative_score);
} else if (asmtInstance.getValue(scoreFieldToSet) !== null && qualitative_score == '') {
asmtInstance.setValue(scoreFieldToSet, qualitative_score);
} else if (asmtInstance.getValue(scoreFieldToSet) != qualitative_score) {
asmtInstance.setValue(scoreFieldToSet, qualitative_score);
}
}
if ((asmtTypeObject.contribution == '3' || asmtTypeObject.contribution == '1') && asmtResponse.assessment_type != '2') {
// If asmt type has contri of BOTH/Quant, get ale
var quantitative_scoring_formula = asmtTypeObject.quantitative_scoring_logic;
var quant_score = this._getAsmtTypeScore(quantitative_scoring_formula, 'quantitative_response', asmt_instance_id, asmt_type, '1', asmtTypeObject.id);
var refCurrCode = asmtInstance.inherent_computed_ale.getReferenceCurrencyCode();
// Set corresponding ale field in insatnce
if (quant_score == '' && asmtInstance.getValue(aleFieldToSet) != '0') {
asmtInstance.setValue(aleFieldToSet, '');
} else if (asmtInstance.getValue(aleFieldToSet) != quant_score) {
asmtInstance.setValue(aleFieldToSet, refCurrCode + ";" + quant_score);
}
}
} else if (asmtTypeObject.contribution == '3') {
// If assessment type contribution is BOTH, set score and ale to ''
if (asmtInstance.getValue(ratingFieldToSet) !== null) {
asmtInstance.setValue(ratingFieldToSet, '');
}
if (asmtResponse.assessment_type != '2' && (asmtInstance.getValue(aleFieldToSet) != '0')) {
asmtInstance.setValue(aleFieldToSet, '');
}
if (asmtInstance.getValue(scoreFieldToSet) !== null) {
asmtInstance.setValue(scoreFieldToSet, '');
}
} else if (asmtTypeObject.contribution == '2') {
// If assessment type contribution is Qualitative, set score to ''
if (asmtInstance.getValue(ratingFieldToSet) !== null) {
asmtInstance.setValue(ratingFieldToSet, '');
}
if (asmtInstance.getValue(scoreFieldToSet) !== null) {
asmtInstance.setValue(scoreFieldToSet, '');
}
} else {
// If assessment type contribution is Quantitative, set ale to ''
if (asmtInstance.getValue(aleFieldToSet) != '0') {
asmtInstance.setValue(aleFieldToSet, '');
}
}
asmtInstance.update();
},
// To get rating given a score value
_getRatingScore: function(asmtType, score) {
if (score === '') {
return '';
}
var rating = '';
var ratings = new GlideRecord('sn_risk_advanced_rating_criteria');
ratings.addQuery('assessment_type', asmtType);
ratings.orderByDesc('lower_interval');
ratings.addQuery('lower_interval', '<=', score);
ratings.setLimit(1);
ratings.query();
if (ratings.next()) {
rating = ratings.getUniqueValue();
} else {
// If the score is less than least lower interval, return the least one
ratings = new GlideRecord('sn_risk_advanced_rating_criteria');
ratings.addQuery('assessment_type', asmtType);
ratings.orderBy('lower_interval');
ratings.setLimit(1);
ratings.query();
if (ratings.next()) {
rating = ratings.getUniqueValue();
}
}
return rating;
},
// To get scores/ale from root responses given a scoring logic
_getAsmtTypeScore: function(scoring_logic, qualOrQuantField, asmt_instance_id, asmt_type, qualOrQuant, asmt_type_id) {
var score;
switch (scoring_logic) {
case 'SUM':
case 'MAX':
case 'MIN':
case 'AVG':
score = this._getAggregateofRootResponseScores(scoring_logic, qualOrQuantField, asmt_instance_id, asmt_type);
break;
case 'WEIGHTED-AVG':
var sum = this._getAggregateofRootResponseScores('SUM', qualOrQuantField, asmt_instance_id, asmt_type);
if (sum == '') {
score = '';
} else {
score = this._getWeightedAverageofRootResponseScores(sum, asmt_instance_id, qualOrQuant, asmt_type, qualOrQuantField);
}
break;
case 'PRODUCT':
score = this._getProductOfRootResponseScores(asmt_instance_id, asmt_type, qualOrQuantField);
break;
case 'SCRIPT':
score = this._executeAndGetScoresForAsmtInstance(asmt_instance_id, qualOrQuant, asmt_type, asmt_type_id);
}
return score;
},
// To execute and calculate the score from script
_executeAndGetScoresForAsmtInstance: function(asmt_instance_id, qualOrQuant, asmt_type, asmt_type_id) {
var score = '';
var response;
var evaluator = new GlideScopedEvaluator();
// Put values from all root response into the script
var rootResponses = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
rootResponses.addQuery('assessment_instance_id', asmt_instance_id);
rootResponses.addQuery('assessment_type', asmt_type);
rootResponses.addEncodedQuery('factor.factor_contributionIN3,' + qualOrQuant);
rootResponses.addNullQuery('parent_instance_response');
rootResponses.query();
while (rootResponses.next()) {
if (qualOrQuant == '1') {
if (rootResponses.getValue('quantitative_response') === null) {
evaluator.putVariable(rootResponses.factor.number + '', 0);
} else {
evaluator.putVariable(rootResponses.factor.number + '', parseFloat(rootResponses.quantitative_response + ''));
}
} else {
if (rootResponses.getValue('qualitative_response') === null) {
evaluator.putVariable(rootResponses.factor.number + '', 0);
} else {
evaluator.putVariable(rootResponses.factor.number + '', parseFloat(rootResponses.qualitative_response + ''));
}
}
}
evaluator.putVariable('score', null);
evaluator.putVariable('result', {});
evaluator.putVariable('asmtId', asmt_instance_id);
var assessmentType = new GlideRecord('sn_risk_advanced_assessment_type');
assessmentType.get(asmt_type_id);
if (qualOrQuant == '2') {
evaluator.evaluateScript(assessmentType, 'qualitative_script', null);
} else {
evaluator.evaluateScript(assessmentType, 'quantitative_script', null);
}
var result = evaluator.getVariable('result');
if (result.error) {
gs.info(gs.getMessage("Divide by zero error occured in assessment instance for ID: {0} and assessment type ID: {1}", [asmt_instance_id, asmt_type_id]));
} else {
// If there is no error, then get the score
score = evaluator.getVariable('score');
}
return score;
},
// To calculate the product of root responses for a given asmt instance and type
_getProductOfRootResponseScores: function(asmt_instance_id, asmt_type, qualOrQuantField) {
var product = 1;
// Get number of eligible child responses
var rootResponses = this._getEligibleRootResponsesForCalculation(asmt_instance_id, asmt_type, qualOrQuantField);
if (!rootResponses.hasNext()) {
return '';
}
while (rootResponses.next()) {
product *= rootResponses.getValue(qualOrQuantField);
}
return product + '';
},
// To calculate weighted average of root responses
_getWeightedAverageofRootResponseScores: function(sum, asmt_instance_id, qualOrQuant, asmt_type, qualOrQuantField) {
if (sum == 0) {
return '0';
}
var sumOfWeights = 0;
// Get iterator of eligible root responses
var rootResponses = this._getEligibleRootResponsesForCalculation(asmt_instance_id, asmt_type, qualOrQuantField);
if (!rootResponses.hasNext()) {
return '';
}
while (rootResponses.next()) {
if (qualOrQuant == '2') {
// If response is qualitative, use qual weighting factor
if (rootResponses.isValidField('control') && rootResponses.control != '') {
// If control asessment and type is individual control, use control weighting
var controlWeight = rootResponses.control.weighting;
if (gs.nil(controlWeight))
controlWeight = 100;
sumOfWeights += controlWeight / 100;
} else
sumOfWeights += rootResponses.factor.weighting_factor / 100;
} else {
// If response is quant, use quant weighting factor
sumOfWeights += rootResponses.factor.quantitative_weighting_factor / 100;
}
}
if (sumOfWeights == 0) {
return '';
}
return (sum / sumOfWeights) + '';
},
// To get GlideRecord iterator to do aggregation of root responses for weighted avg and product
_getEligibleRootResponsesForCalculation: function(asmt_instance_id, asmt_type, qualOrQuantField) {
var rootResponses = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
rootResponses.addQuery('assessment_instance_id', asmt_instance_id);
rootResponses.addQuery('assessment_type', asmt_type);
rootResponses.addNotNullQuery(qualOrQuantField);
rootResponses.addNullQuery('parent_instance_response');
rootResponses.query();
return rootResponses;
},
// To get aggregated score/ale from root responses under asmt instance
_getAggregateofRootResponseScores: function(scoring_logic, qualOrQuantField, asmt_instance_id, asmt_type) {
var rootResponses = new GlideAggregate('sn_risk_advanced_risk_assessment_instance_response');
rootResponses.addAggregate(scoring_logic, qualOrQuantField);
rootResponses.addQuery('assessment_instance_id', asmt_instance_id);
rootResponses.addQuery('assessment_type', asmt_type);
rootResponses.addNullQuery('parent_instance_response');
rootResponses.setGroup(false);
rootResponses.query();
var aggregateVar;
if (rootResponses.next()) {
aggregateVar = rootResponses.getAggregate(scoring_logic, qualOrQuantField);
}
if (isNaN(aggregateVar)) {
aggregateVar = '';
}
return aggregateVar;
},
// To calculate and set parent response scores
calculateParentResponseScores: function(asmtResponse) {
return this._calculateParentResponseScores(asmtResponse);
},
_calculateParentResponseScores: function(asmtResponse) {
// Get response factor contribution
var responseContribution = asmtResponse.factor.factor_contribution + '';
// Get parent response ID and parent response instance
var parent_response_id = asmtResponse.parent_instance_response;
var parentResponse = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
parentResponse.get(parent_response_id);
// Get parent response factor contribution
var parentResponseFactorContribution = parentResponse.factor.factor_contribution + '';
// Check if parent response has to be calculated using logic/script
if (this._parentResponseScoreToBeCalculated(parent_response_id, parentResponseFactorContribution)) {
var parentResponseFactorId = parentResponse.factor + '';
// Parent response can only have factor as group factor
var groupFactor = new GlideRecord('sn_risk_advanced_group_factor');
groupFactor.get(parentResponseFactorId);
// If factor contri is Quantitative or Both, calculate quantitative score
if (parentResponseFactorContribution == '1' || parentResponseFactorContribution == '3') {
var quantitative_formula = groupFactor.quantitative_formula + '';
var quantitative_score = this._getParentResponseScore(parent_response_id, quantitative_formula, 'quantitative_response', '1', groupFactor);
if (quantitative_score != '') {
quantitative_score = (quantitative_score * groupFactor.quantitative_weighting_factor) / 100;
}
if (quantitative_score == '' && !parentResponse.quantitative_response.nil() || quantitative_score != '' && parentResponse.quantitative_response.nil() || quantitative_score != parentResponse.getValue('quantitative_response')) {
parentResponse.quantitative_response = quantitative_score;
}
}
// If factor contribution is Qualitative or Both, calculate qualitative score
if (parentResponseFactorContribution == '2' || parentResponseFactorContribution == '3') {
var qualitative_formula = groupFactor.qualitative_formula + '';
var qualitative_score = this._getParentResponseScore(parent_response_id, qualitative_formula, 'qualitative_response', '2', groupFactor);
// Transform the parent response
qualitative_score = this._getTransformedScore(parentResponse, qualitative_score);
if (qualitative_score != '') {
if (parentResponse.getValue('assessment_type') == '2' && this._shouldConsiderControlWeightage(parentResponse.assessment_instance_id.risk_assessment_methodology + '')) {
//If it is individual control assessment consider control weightage instead of group factor weightage
var controlWeightage = parentResponse.control.weighting;
if (gs.nil(controlWeightage))
controlWeightage = 100;
qualitative_score = qualitative_score * (controlWeightage) / 100;
} else
qualitative_score = (qualitative_score * groupFactor.weighting_factor) / 100;
}
if (qualitative_score == '' && !parentResponse.qualitative_response.nil() || qualitative_score != '' && parentResponse.qualitative_response.nil() || qualitative_score != parentResponse.getValue('qualitative_response')) {
parentResponse.qualitative_response = qualitative_score;
}
}
} else if (parentResponseFactorContribution == '3') {
// If mandatory child responses are unanswered, make parent response scores ''. This is being done so that if any mandatory child has become '', existing parent response scores become invalid
if (!parentResponse.qualitative_response.nil()) {
parentResponse.qualitative_response = '';
}
if (!parentResponse.quantitative_response.nil()) {
parentResponse.quantitative_response = '';
}
} else if (parentResponseFactorContribution == '2') {
// If parent FC is qualitative,
if (!parentResponse.qualitative_response.nil()) {
parentResponse.qualitative_response = '';
}
} else {
if (!parentResponse.quantitative_response.nil()) {
parentResponse.quantitative_response = '';
}
}
// This update will happen only if there is a change in GlideElement. So if the fields were empty before as well, no update will happen.
if (parentResponse.qualitative_response.changes() || parentResponse.quantitative_response.changes()) {
parentResponse.update();
}
},
_shouldConsiderControlWeightage: function(ramId) {
var asmtType = new GlideRecord('sn_risk_advanced_control_assessment');
asmtType.addQuery('risk_assessment_methodology', ramId);
asmtType.query();
return asmtType.next() && asmtType.getValue('control_assessment_methodology') == 'individual_control_assessment' && asmtType.getValue('qualitative_scoring_logic') == 'WEIGHTED-AVG';
},
// To get aggregated scores for child responses
_getParentResponseScore: function(parentResponseId, formula, qualOrQuantField, qualOrQuant, groupFactor) {
var score;
switch (formula) {
case 'SUM':
case 'MAX':
case 'MIN':
case 'AVG':
score = this._getAggregateofChildScores(parentResponseId, qualOrQuantField, formula);
break;
case 'WEIGHTED-AVG':
var sum = this._getAggregateofChildScores(parentResponseId, qualOrQuantField, 'SUM');
if (sum == '') {
score = '';
} else {
score = this._getWeightedAverageofChildScores(sum, parentResponseId, qualOrQuant);
}
break;
case 'PRODUCT':
score = this._getProductOfchildScores(parentResponseId, qualOrQuant, qualOrQuantField);
break;
case 'SCRIPT':
score = this._executeAndGetScores(parentResponseId, qualOrQuant, groupFactor);
}
return score;
},
// To execute and calculate the score from script
_executeAndGetScores: function(parentResponseId, qualOrQuant, groupFactor) {
var score = '';
var response;
var evaluator = new GlideScopedEvaluator();
// Put values from all child response into the script
var childResponses = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
childResponses.addQuery('parent_instance_response', parentResponseId);
childResponses.addEncodedQuery('factor.factor_contributionIN3,' + qualOrQuant);
childResponses.query();
while (childResponses.next()) {
if (qualOrQuant == '1') {
if (childResponses.getValue('quantitative_response') === null) {
evaluator.putVariable(childResponses.factor.number + '', 0);
} else {
evaluator.putVariable(childResponses.factor.number + '', parseFloat(childResponses.quantitative_response + ''));
}
} else {
if (childResponses.getValue('qualitative_response') === null) {
evaluator.putVariable(childResponses.factor.number + '', 0);
} else {
evaluator.putVariable(childResponses.factor.number + '', parseFloat(childResponses.qualitative_response + ''));
}
}
}
evaluator.putVariable('score', null);
evaluator.putVariable('result', {});
if (qualOrQuant == '2') {
evaluator.evaluateScript(groupFactor, 'qualitative_script', null);
} else {
evaluator.evaluateScript(groupFactor, 'quantitative_script', null);
}
var result = evaluator.getVariable('result');
if (result.error) {
gs.info(gs.getMessage("Divide by zero error occured in assessment instance response for ID: {0}", parentResponseId));
} else {
// If there is no error, then get the score
score = evaluator.getVariable('score');
}
return score;
},
// To get GlideRecord object for all child responses which should be used to calculate the parent score
_getEligibleChildResponsesForCalculation: function(parentResponseId, qualOrQuant) {
var childResponses = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
childResponses.addQuery('parent_instance_response', parentResponseId);
childResponses.addEncodedQuery('factor.factor_contributionIN3,' + qualOrQuant);
if (qualOrQuant == '2') {
childResponses.addNotNullQuery('qualitative_response');
} else {
childResponses.addNotNullQuery('quantitative_response');
}
childResponses.query();
return childResponses;
},
// To get product of child responses
_getProductOfchildScores: function(parentResponseId, qualOrQuant, qualOrQuantField) {
var product = 1;
// Get eligible child responses iterator
var childResponses = this._getEligibleChildResponsesForCalculation(parentResponseId, qualOrQuant);
if (!childResponses.hasNext()) {
return '';
}
while (childResponses.next()) {
product *= childResponses.getValue(qualOrQuantField);
}
return product + '';
},
// To get weighted average of child responses
_getWeightedAverageofChildScores: function(sum, parentResponseId, qualOrQuant) {
if (sum == 0) {
return '0';
}
var sumOfWeights = 0;
// Get eligible child responses iterator
var childResponses = this._getEligibleChildResponsesForCalculation(parentResponseId, qualOrQuant);
if (!childResponses.hasNext()) {
return '';
}
while (childResponses.next()) {
if (qualOrQuant == '2') {
sumOfWeights += childResponses.factor.weighting_factor / 100;
} else {
sumOfWeights += childResponses.factor.quantitative_weighting_factor / 100;
}
}
// Add exception message if sum of weights is 0
if (sumOfWeights == 0) {
return '';
}
return (sum / sumOfWeights) + '';
},
// To get Aggregate of child scores for different aggrgeration formula
_getAggregateofChildScores: function(parentResponseId, qualOrQuantField, aggregate) {
var childResponses = new GlideAggregate('sn_risk_advanced_risk_assessment_instance_response');
childResponses.addAggregate(aggregate, qualOrQuantField);
childResponses.addQuery('parent_instance_response', parentResponseId);
childResponses.setGroup(false);
childResponses.query();
var aggregateVar;
if (childResponses.next()) {
aggregateVar = childResponses.getAggregate(aggregate, qualOrQuantField);
}
if (isNaN(aggregateVar)) {
aggregateVar = '';
}
return aggregateVar;
},
// Is it required to calculate the parent response scores
_parentResponseScoreToBeCalculated: function(parentResponseId, parentResponseFactorContribution) {
// If count of mandatory child responses with no response > 0, Do not calculate
var responses = new GlideAggregate('sn_risk_advanced_risk_assessment_instance_response');
responses.addAggregate('COUNT');
responses.addQuery('parent_instance_response', parentResponseId);
responses.addQuery('factor.mandatory_response', true);
// If Parent Fac is BOTH, all mandatory child should be filled
if (parentResponseFactorContribution == '3') {
responses.addEncodedQuery('factor.factor_contributionIN1,2,3');
} else {
// If PF is Qual, all mandatory Qual and Both should be filled
// If PF is Quant, all mandatory Quant and both should be filled
responses.addEncodedQuery('factor.factor_contributionIN3,' + parentResponseFactorContribution);
}
responses.addNullQuery('factor_response');
responses.setGroup(false);
responses.query();
var count = 0;
if (responses.next()) {
count = parseInt(responses.getAggregate('COUNT'));
}
return (count == 0);
},
// To update the responses in database
commitResponseToDB: function(responseId, responseObject) {
return this._commitResponseToDB(responseId, responseObject);
},
_commitResponseToDB: function(responseId, responseObject) {
var asmtResponse = new GlideRecord('sn_risk_advanced_risk_assessment_instance_response');
asmtResponse.get(responseId);
if (responseObject.hasOwnProperty('additional_comments')) {
asmtResponse.additional_comments = responseObject.additional_comments;
}
if (responseObject.hasOwnProperty('factor_response')) {
asmtResponse.factor_response = responseObject.factor_response;
}
return asmtResponse.update();
},
// To calculate qualitative response score
calculateQualitativeResponse: function(asmtResponse) {
return this._calculateQualitativeResponse(asmtResponse);
},
_calculateQualitativeResponse: function(asmtResponse) {
var response = asmtResponse.factor_response + '';
// If response is '', set qualitative response to ''
if (response == '') {
asmtResponse.qualitative_response = '';
} else {
var score = this._getQuantOrQualScore(asmtResponse);
score = this._getTransformedScore(asmtResponse, score);
// Get score for percentage type user response if no transformation happened
if (!asmtResponse.factor.transform_score && asmtResponse.factor.sys_class_name != "sn_risk_advanced_group_factor" &&
asmtResponse.factor.user_response == '5') {
score = score / 100;
}
// Get weighted score
if (asmtResponse.assessment_type + '' == '2' && this._shouldConsiderControlWeightage(asmtResponse.assessment_instance_id.risk_assessment_methodology + '')) {
// If assessment is individual control assessment and is not based on a group factor then consider control weightage else consider factor weightage
if (gs.nil(asmtResponse.getValue('parent_instance_response'))) {
var controlWeightage = asmtResponse.control.weighting;
if (gs.nil(controlWeightage))
controlWeightage = 100;
asmtResponse.qualitative_response = score * (controlWeightage) / 100;
return;
}
}
asmtResponse.qualitative_response = score * asmtResponse.factor.weighting_factor / 100;
}
},
// Transform the score based on transformation criteria
_getTransformedScore: function(asmtResponse, score) {
if (gs.nil(score)) {
return '';
}
var transformedScore = score;
// If transform score flag is checked, then do transformation
if (asmtResponse.factor.transform_score) {
var criteria = new GlideRecord('sn_risk_advanced_transformation_criteria');
criteria.addQuery('factor', asmtResponse.factor);
criteria.orderByDesc('lower_interval');
criteria.addQuery('lower_interval', '<=', score);
criteria.setLimit(1);
criteria.query();
if (criteria.next()) {
transformedScore = criteria.score + '';
asmtResponse.transformation_criteria = criteria.getUniqueValue();
} else {
// If the score is less than least lower interval, return the least one
criteria = new GlideRecord('sn_risk_advanced_transformation_criteria');
criteria.addQuery('factor', asmtResponse.factor);
criteria.orderBy('lower_interval');
criteria.setLimit(1);
criteria.query();
if (criteria.next()) {
transformedScore = criteria.score + '';
asmtResponse.transformation_criteria = criteria.getUniqueValue();
}
}
}
return transformedScore;
},
// To calculate qualitative response score
calculateQuantitativeResponse: function(asmtResponse) {
return this._calculateQuantitativeResponse(asmtResponse);
},
_calculateQuantitativeResponse: function(asmtResponse) {
var response = asmtResponse.factor_response + '';
// If response if empty, set quant response to ''
if (response == '') {
asmtResponse.quantitative_response = '';
} else {
var score = this._getQuantOrQualScore(asmtResponse);
// Get score for percentage type user response
if (asmtResponse.factor.sys_class_name != 'sn_risk_advanced_group_factor' && asmtResponse.factor.user_response == '5') {
score = score / 100;
}
// Get weighted score
asmtResponse.quantitative_response = score * asmtResponse.factor.quantitative_weighting_factor / 100;
}
},
// To get Quantitative score for asmt response
_getQuantOrQualScore: function(asmtResponse) {
var score;
var UserResponseType = null;
var response = asmtResponse.factor_response + '';
if (asmtResponse.factor.sys_class_name == 'sn_risk_advanced_manual_factor' || asmtResponse.factor.sys_class_name == 'sn_risk_advanced_automated_scripted_factor' || asmtResponse.factor.sys_class_name == 'sn_risk_advanced_automated_query_factor') {
// If Manual factor, then assign response type
UserResponseType = asmtResponse.factor.user_response + '';
}
if (UserResponseType == '4') {
// If currency then get reference currency value
score = global.getCurrencyFilter('', '', response) + '';
} else {
score = response;
}
return score;
},
_copyScoreToAssessmentSummaryFieldsForInherent: function(asmt) {
if (asmt.final_inherent_score.changes()) {
var gr = new GlideRecord("sn_risk_advanced_inherent_assessment");
gr.addQuery("risk_assessment_methodology", asmt.risk_assessment_methodology);
gr.query();
if (gr.next()) {
asmt.summary_inherent_risk = this._getRatingScore(gr.getUniqueValue(), asmt.final_inherent_score + '');
}
}
},
_copyScoreToAssessmentSummaryFieldsForControl: function(asmt) {
if (asmt.final_control_score.changes()) {
var gr1 = new GlideRecord("sn_risk_advanced_control_assessment");
gr1.addQuery("risk_assessment_methodology", asmt.risk_assessment_methodology);
gr1.query();
if (gr1.next()) {
asmt.summary_control_effectiveness = this._getRatingScore(gr1.getUniqueValue(), asmt.final_control_score + '');
}
}
},
_copyScoreToAssessmentSummaryFieldsForResidual: function(asmt) {
if (asmt.final_residual_score.changes()) {
var gr2 = new GlideRecord("sn_risk_advanced_residual_assessment");
gr2.addQuery("risk_assessment_methodology", asmt.risk_assessment_methodology);
gr2.query();
if (gr2.next()) {
asmt.summary_residual_risk = this._getRatingScore(gr2.getUniqueValue(), asmt.final_residual_score + '');
}
}
},
_copyScoreToAssessmentSummaryFieldsForTarget: function(asmt) {
if (asmt.final_target_score.changes()) {
var gr = new GlideRecord("sn_risk_advanced_target_assessment");
gr.addQuery("risk_assessment_methodology", asmt.risk_assessment_methodology);
gr.query();
if (gr.next()) {
asmt.summary_target_risk = this._getRatingScore(gr.getUniqueValue(), asmt.final_target_score + '');
}
}
},
// To calculate Quantitative score for residual asmt
_autoCalculateResidualAssessment: function(asmt) {
var gr = new GlideRecord("sn_risk_advanced_residual_assessment");
gr.addQuery("risk_assessment_methodology", current.risk_assessment_methodology);
gr.query();
if (gr.next()) {
if (gr.getValue('calculate_based_on') == 'inherent_control') {
if (asmt.final_inherent_score.nil()) {
asmt.residual_computed_score = "";
asmt.residual_computed_risk = "";
} else if (asmt.final_control_score.nil()) {
asmt.residual_computed_score = asmt.final_inherent_score;
asmt.residual_computed_risk = this.getRatingScore(gr.getUniqueValue(), asmt.residual_computed_score + '');
} else {
if (gr.getValue('qualitative_scoring_type') == "inherent_control_difference") {
asmt.residual_computed_score = (parseFloat(asmt.getValue("final_inherent_score")) - parseFloat(asmt.getValue("final_control_score")));
} else if (gr.getValue('qualitative_scoring_type') == "inherent_control_division") {
if (parseFloat(asmt.getValue("final_control_score")) != 0) {
asmt.residual_computed_score = (parseFloat(asmt.getValue("final_inherent_score")) / parseFloat(asmt.getValue("final_control_score")));
}
} else if (gr.getValue('qualitative_scoring_type') == "lookup_matrix") {
var matrix = new GlideRecord("sn_risk_advanced_residual_assessment_matrix");
matrix.addQuery("inherent_risk", asmt.summary_inherent_risk);
matrix.addQuery("control_effectiveness", asmt.summary_control_effectiveness);
matrix.addQuery("sn_risk_advanced_assessment_type", gr.getUniqueValue());
matrix.query();
if (matrix.hasNext()) {
matrix.next();
asmt.residual_computed_score = matrix.score + '';
}
} else if (gr.getValue('qualitative_scoring_type') == "script") {
var evaluator = new GlideScopedEvaluator();
evaluator.putVariable('score', null);
evaluator.putVariable('result', {});
evaluator.putVariable('asmtId', asmt.getUniqueValue());
evaluator.putVariable('inherent_score', parseFloat(asmt.getValue("final_inherent_score")));
evaluator.putVariable('control_effectiveness', parseFloat(asmt.getValue("final_control_score")));
evaluator.evaluateScript(gr, 'qualitative_scoring_logic_script', null);
var result = evaluator.getVariable('result');
if (result.error) {
gs.info(gs.getMessage("Error occured in assessment instance for ID: {0} in the residual scoring script", asmt.getUniqueValue()));
} else {
// If there is no error, then get the score
score = evaluator.getVariable('score');
asmt.residual_computed_score = parseFloat(score);
}
}
asmt.residual_computed_risk = this.getRatingScore(gr.getUniqueValue(), asmt.residual_computed_score + '');
}
return;
}
}
},
type: 'RiskAssessmentScoringUtilsBase'
};
Sys ID
2d498bd4536100100b39ddeeff7b124c