Skip to content

Instantly share code, notes, and snippets.

@rafzk
Last active October 1, 2019 22:06
Show Gist options
  • Select an option

  • Save rafzk/40a819bed8950c6233364aa6232f6a77 to your computer and use it in GitHub Desktop.

Select an option

Save rafzk/40a819bed8950c6233364aa6232f6a77 to your computer and use it in GitHub Desktop.
[Create Current Scoring for Risk Management]

Create Current Scoring for Risk Management

Introduction

In this snippet you will create a current scoring (similar to inherent or residual) using same functions and logic.

Step 1: Create the following fields in Risk table

Go to sn_risk_risk.config > Dictionary entries > Click New

Make sure you have the update in the correct application. (GRC: Risk Management).

Field Type Reference
u_current_ale Currency
u_current_aro Currency
u_current_sle Currency
u_current_impact Reference Risk Criteria
u_current_likelihood Reference Risk Criteria
u_current_score Reference Risk Criteria

Step 2: Reporting - Clone Risk Overview dashboard

Go to pa_dashboard and get ready to clone a out of the box record

Make sure you have the update in the correct application. (GRC: Risk Management).

  • Clone Risk Overview widget and rename to Custom Risk Overview.
  • Add a new tab named "Current Scoring"
  • Click on Save button to save the change.

Step 3: Reporting - Clone inherent_heatmap UI page

Go to sys_widgets and get ready to clone a out of the box record

Make sure you have the update in the correct application. (GRC: Risk Management).

  • Clone Inherent Heatmap widget by clicking Insert and Stay menu action.
  • Name: Current Risk Heatmap
  • Click on Save button to save the change.

Script

  • Copy and paste below Script in Widget's Script section
function sections() {
    return {
		'Current Risk Heatmap' : { 'name' : 'current_heatmap' }
    };
}

function render() {
	return renderer.getRenderedPage( 'sn_risk_current_heatmap');  
}

function getEditLink() {
	return "sys_ui_page.do?sysparm_query=name=current_heatmap";
}

Step 4: Reporting - Clone inherent_heatmap UI page

Go to sys_ui_page and get ready to clone a out of the box record

Make sure you have the update in the correct application. (GRC: Risk Management).

  • Clone inherent_heatmap UI page by clicking Insert and Stay menu action.
  • Name: current_heatmap
  • Click on Save button to save the change.

Endpoint

  • Copy and paste below Endpoint in UI page section
sn_risk_current_heatmap.do

Body HTML template

  • Copy and paste below HTML Code in Widget's HTML Template section
<?xml version="1.0" encoding="utf-8" ?>
<j:jelly trim="false" xmlns:j="jelly:core" xmlns:g="glide" xmlns:j2="null" xmlns:g2="null">
	<g:requires name="styles/heisenberg/heisenberg_all.css" includes="true" />
	<script language="javascript" src="sn_risk.RiskHeatmapUtils.jsdbx" />
	<style>
		#currentRiskHighChartContainer text tspan {
			stroke-width: 1px;
		}
	</style>
	
	<g2:evaluate var="jvar_riskHighChartData">
		var risk = new sn_risk.RiskHeatmap().getRiskHeatmapData('current', '', true); 
		new global.JSON().encode(risk);
	</g2:evaluate>
	<g2:evaluate var="jvar_riskXAxisCategories">
		var xAxis = new sn_risk.RiskHeatmap().getRiskHeatmapXAxisCategories();  
		new global.JSON().encode(xAxis);
	</g2:evaluate>
	<g2:evaluate var="jvar_riskYAxisCategories">
		var yAxis = new sn_risk.RiskHeatmap().getRiskHeatmapYAxisCategories(); 
		new global.JSON().encode(yAxis);
	</g2:evaluate>
	
    <div id="currentRiskHighChartContainer" name="currentRiskHighChartContainer" style="min-width: 310px; height: 400px; max-width: 600px; margin: 0 auto"> 
    </div>
	
   
</j:jelly>

Client script

  • Copy and Paste below script in Client Script Section
(function($){
	var chart;

	chart = new Highcharts.Chart({
		chart: {
			renderTo: "currentRiskHighChartContainer",
			type: 'heatmap',
			marginTop: 12,
			marginBottom: 60,
			plotBackgroundColor: 'none',
			events:{
				load:function() {
					var points = this.series[0].data,
					lenY = this.yAxis[0].tickPositions.length - 1,
					lenX = this.xAxis[0].tickPositions.length - 1,
					x = lenX,
					tmpX = 0,
					y = 0,
					j = 0;
					
					$.each(points, function(i, p){
						var color = p.color;
						p.update({
							color: color
						},false);
					});
					
					this.isDirty = true;
					this.redraw();
				}
			}
		},
		plotOptions: {
			series: {
				events: {
					click: function (event) {
						document.location.href = event.point.url;
					}
				}
			}
		},
		title: {
			align:'center',
			text: '',
			
			style: {
				color: 'black',
				fontSize: '12pt'
			}
			
		},
		
		xAxis: {
			categories: JSON.parse('$[HTML, JS:jvar_riskXAxisCategories]'),
			title: {
				enabled: true,
				text: '<span>Impact</span>'
			}
		},
		
		yAxis: {
			categories: JSON.parse('$[HTML, JS:jvar_riskYAxisCategories]'),
			title: {
				enabled: true,
				text: '<span>Likelihood</span>'
			}
		},
		
		tooltip: {
			formatter: function () {
				var msg = new GwtMessage().getMessage('Count: {0}', this.point.value)
				+ '<br>' + 
				new GwtMessage().getMessage('Impact: {0}', this.series.yAxis.categories[this.point.y])
				+ '<br>' + 
				new GwtMessage().getMessage('Likelihood: {0}', this.series.xAxis.categories[this.point.x]);
				return msg;
			}
		},
		credits: {
			enabled: false
		},
		/*want to make this part dynamically populated*/
		series:[{
			data:[],
			cursor: 'pointer',
			showInLegend: false,			
			dataLabels: {
				enabled: true,
				color: 'black',
				type: 'heatmap',
				backgroundColor: 'none',
				style: {
					textShadow: 'none'
				}
			}
			
		}]
		
	});
	
	sn_risk.RiskHeatmapUtils.updateHeatmap(chart, 'current', true);
	
	CustomEvent.on('dashboard_filter.removed', function(filterMessage){	
		sn_risk.RiskHeatmapUtils.onRemoveEvent(chart, filterMessage, 'current', true);		
	});
	
	CustomEvent.on('dashboard_filter.added', function(filterMessage){
		sn_risk.RiskHeatmapUtils.onAddEvent(chart, filterMessage, 'current', true);
	});	
	
})(jQuery);

Processing Script

  • Copy and Paste below Server-Side Script in Processing Script Section
// empty
  • Click on Save button to save the change.

Step 5: Scripting - Edit RiskHeatMap

Go to System Definition > Script Include

  • Search for RiskHeatMapand open the record.
  • Copy and Paste below Script in Script Include Script Section
var RiskHeatmap = Class.create();
RiskHeatmap.prototype = Object.extendsObject(RiskHeatmapBase, {

    // Overwrite current method to include current as heatmapType
	_getRiskHeatmapData: function(heatmapType, filter, includeColor){
		var riskData = [];
		var riskImpactFieldName = '';
		var riskLikelihoodFieldName = '';
		
		if (heatmapType == 'inherent'){
			riskImpactFieldName = 'impact';
			riskLikelihoodFieldName = 'likelihood';
		}
		else if(heatmapType == 'residual'){
			riskImpactFieldName = 'residual_impact';
			riskLikelihoodFieldName = 'residual_likelihood';
		} else if(heatmapType == 'current'){
			riskImpactFieldName = 'u_current_impact';
			riskLikelihoodFieldName = 'u_current_likelihood';
		} else
		return riskData;
		
		var likelihood =  new GlideRecord('sn_risk_criteria');
		likelihood.addQuery('type', 'likelihood');
		likelihood.orderByDesc('order');
		
		likelihood.query();
		
		for(var i = 0; i < likelihood.getRowCount(); i++){
			likelihood.next();
			
			var impact =  new GlideRecord('sn_risk_criteria');
			impact.addQuery('type', 'impact');
			impact.orderByDesc('order');
			
			impact.query();
			for(var j = 0; j < impact.getRowCount(); j++){
				
				impact.next();
				var risk = new GlideAggregate('sn_risk_risk');
				var count = 0;
				risk.addQuery(riskImpactFieldName, impact.getUniqueValue());
				risk.addQuery(riskLikelihoodFieldName, likelihood.getUniqueValue());
				
				if (filter)				
					risk.addEncodedQuery(filter);

				risk.addAggregate('COUNT');
				risk.query();
				if (risk.next())
					count = risk.getAggregate('COUNT');
				
				var riskColor = this._getRiskColor(impact.getUniqueValue(), likelihood.getUniqueValue());
				var riskUrl = 'sn_risk_risk_list.do?sysparm_query=' + riskImpactFieldName + '%3D' + impact.getUniqueValue()
				+ '%5E' + riskLikelihoodFieldName + '%3D' + likelihood.getUniqueValue();
				
				if (filter)
					riskUrl += '%5E' + filter;
				if (includeColor)
					riskData.push({x:i, y:j, value:count, color: riskColor, url:riskUrl});
				else
					riskData.push({x:i, y:j, value:count, url:riskUrl});
				}
			}
			
			return riskData;
		},





    /** Override base class functions here **/

    type: 'RiskHeatmap'
});
  • Click on Save button to save the change.

Step 6: Scripting - Create new RiskFormUtils

Go to System UI > UI Scripts > Click New

  • Id: WR_RiskFormUtilsV2
  • Copy and Paste below Script in UI Script Script Section
var sn_risk = sn_risk || {};

sn_risk.WR_RiskFormUtilsV2 = (function() {
"use strict";

return {

	calculateALE: function(currency) {

		var resALE = g_form.getValue('sys_readonly.sn_risk_risk.residual_ale');
		var inALE = g_form.getValue('sys_readonly.sn_risk_risk.inherent_ale');
		var ccr = g_form.getValue('calculated_risk_factor');

		resALE = parseFloat(resALE.replace(/[^\d\.]/g,''));
		inALE = parseFloat(inALE.replace(/[^\d\.]/g,''));

		var calcALE = parseFloat(resALE + ((inALE - resALE) * (ccr / 100)));

		calcALE = calcALE.toFixed(2);
		calcALE = currency + calcALE;

		g_form.setValue('calculated_ale', calcALE.toString());
	},

	synchSymbol: function(fromSLE, toSLE, tableName){	
		var toSLESymbol = g_form.getValue(toSLE + '.currency');
		var fromSLESymbol = g_form.getValue(fromSLE + '.currency');  
		if (toSLESymbol == fromSLESymbol)
			return;

		var val = g_form.getValue(toSLE + '.display');	
		// Strip any special characters in the value
		val = val.replace(new RegExp(g_user_grouping_separator, "g"), "");

		var newSLEVal = fromSLESymbol + ';' + val;
		g_form.setValue(toSLE + ".currency", fromSLESymbol);
		g_form.setValue(toSLE + ".display", val);
		g_form.setValue(toSLE, newSLEVal);

		var id = tableName + '.' + toSLE;
		// these two lines are used to set the right currency value, like GBP;100.00
		// Otherwise the value is set to be 100.00, which won't save the currenct
		var sleElement= document.getElementById(id);
		sleElement.value = newSLEVal;			

	},	

	hideQualitativeFields: function(hideQualitativeFields) {
		var fieldsToHide = [];
		if (hideQualitativeFields) {
			fieldsToHide = ['significance', 'residual_significance', 
							'likelihood', 'residual_likelihood',
							'score', 'residual_score',
							'calculated_score'
							];
		}
		else {
			fieldsToHide = ['inherent_sle', 'residual_sle',
							'inherent_aro', 'residual_aro',
							'inherent_ale', 'residual_ale',
							'calculated_ale',

							'default_inherent_sle', 'default_residual_sle',
							'default_inherent_aro', 'default_residual_aro'
							];
		}
		for (var i = 0; i < fieldsToHide.length; i++)
			g_form.setDisplay(fieldsToHide[i], false);
	}, 

	  updateRiskScore: function(scoreType, fieldName, fieldType, value) {

		            var setFieldName, impactField, likelihooField;
		            var ga = new GlideAjax('RiskUtilsAJAXV2');
		
		            switch(fieldName) {
		
		                case 'u_current_impact':
		                    setFieldName = 'u_current_sle';
		                    ga.addParam('sysparm_name', 'usingQualitative');
		                    ga.addParam('sysparm_prop_name', 'sn_risk.qualitative_impact');
		                    ga.getXML(setFields);
		                    break;
		
		                case 'u_current_likelihood':
		                    setFieldName = 'u_current_aro';
		                    ga.addParam('sysparm_name', 'usingQualitative');
		                    ga.addParam('sysparm_prop_name', 'sn_risk.qualitative_likelihood');
		                    ga.getXML(setFields);
		            }
		
		            function setFields(response) {
		                var answer = response.responseXML.documentElement.getAttribute("answer");
		                if(answer == 'true') {
		
		                    ga = new GlideAjax('RiskUtilsAJAXV2');
		                    ga.addParam('sysparm_name', 'getRiskCriteria');
		                    ga.addParam('sysparm_field_type', fieldType);
		                    ga.addParam('sysparm_field_value', value);
		                    ga.getXMLAnswer(function(answer) {
		
		                        if(answer != false || answer == '0')
		                            g_form.setValue(setFieldName, answer);
		                    });
		
		                    ga = new GlideAjax('RiskUtilsAJAXV2');
		                    ga.addParam('sysparm_name', 'getRiskScore');
		                    ga.addParam('sysparm_impact', g_form.getValue('u_current_impact'));
		                    ga.addParam('sysparm_likelihood', g_form.getValue('u_current_likelihood'));
		                    ga.getXMLAnswer(function(answer) {
		                        g_form.setValue('u_current_score', answer);
		                    });
		                }
		            }
		        },
	
	useQualitativeImpact: function(useQualitativeImpact) {
		jslog("Calling use qualitative impact " + useQualitativeImpact);
		if(useQualitativeImpact) {
			g_form.setDisplay('inherent_sle', false);
			g_form.setDisplay('residual_sle', false);
			g_form.setDisplay('default_inherent_sle', false);
			g_form.setDisplay('default_residual_sle', false);
		}
		else {
			g_form.setDisplay('impact', false);
			g_form.setDisplay('residual_impact', false);
		}
	},

	useQualitativeLikelihood: function(useQualitativeLikelihood) {
		jslog("Calling use qualitative likelihood " + useQualitativeLikelihood);
		if(useQualitativeLikelihood) {
			g_form.setDisplay('inherent_aro', false);
			g_form.setDisplay('residual_aro', false);
			g_form.setDisplay('default_inherent_aro', false);
			g_form.setDisplay('default_residual_aro', false);
		}
		else {
			g_form.setDisplay('likelihood', false);
			g_form.setDisplay('residual_likelihood', false);
		}
	},

	validateRisk: function(fieldType) {
		jslog("Started: " + fieldType);
		fieldType = fieldType + '';
		var isDefault = false;
		var fieldArr = fieldType.split('_');

		if(fieldArr[0] == 'default')
			isDefault = true;

		var inherentField;
		var residualField;
		var inherent; 
		var residual;

		switch(fieldType) {
			case 'likelihood':
			case 'impact':
				residualField = 'residual_' + fieldType;
				inherentField = fieldType;
				setQualitativeValues(inherentField, residualField);
				break;

			case 'residual_likelihood':
			case 'residual_impact':
				residualField = fieldType;
				inherentField = fieldArr[1];
				setQualitativeValues(inherentField, residualField);
				break;

			case 'default_inherent_sle':
			case 'inherent_sle':
				setInherentQuantitativeValues(fieldType, fieldArr);
				setQuantitativeValues(inherentField, residualField);
				doCheck();
				break;

			case 'default_inherent_aro':
			case 'inherent_aro':
				setInherentQuantitativeValues(fieldType, fieldArr);
				setAROValues(inherentField, residualField);
				break;

			case 'default_residual_sle':
			case 'residual_sle':
				setResidualQuantitativeValues(fieldType, fieldArr);
				setQuantitativeValues(inherentField, residualField);
				doCheck();
				break;
			case 'default_residual_aro':
			case 'residual_aro':
				setResidualQuantitativeValues(fieldType, fieldArr);
				setAROValues(inherentField, residualField);
				break;
		}

		function hideErrorBoxes(inherentField, residualField) {
			g_form.hideErrorBox(inherentField);
			g_form.hideErrorBox(residualField);
		}

		function setInherentQuantitativeValues(fieldType, fieldArr) {
			inherentField = fieldType;
			if(isDefault)
				residualField = 'default_residual_' + fieldArr[2];
			else
				residualField = 'residual_' + fieldArr[1];
			hideErrorBoxes(inherentField, residualField);
		}

		function setResidualQuantitativeValues(fieldType, fieldArr) {
			if(isDefault)
				inherentField = 'default_inherent_' + fieldArr[2];
			else
				inherentField = 'inherent_' + fieldArr[1];
			residualField = fieldType;
			hideErrorBoxes(inherentField, residualField);
		}

		function setQuantitativeValues(inherentField, residualField) {
			var rawInherent = g_form.getValue(inherentField);
			var inherentArray = rawInherent.split(';');
			inherent = parseFloat(inherentArray[1].replace(/,/g , ''));
			var rawResidual = g_form.getValue(residualField);
			var residualArray = rawResidual.split(';');
			residual = parseFloat(residualArray[1].replace(/,/g , ''));
		}

		function setQualitativeValues(inherentField, residualField) {
			hideErrorBoxes(inherentField, residualField);
			inherent = false;
			residual = false;
			if(g_form.getValue(inherentField) == '') {
				inherent = 0;
			}
			else {
				g_form.getReference(inherentField, setInherent);
			}
			g_form.getReference(residualField, setResidual);
		}

		function setAROValues(inherentField, residualField) {
			hideErrorBoxes(inherentField, residualField);
			inherent = g_form.getValue(inherentField);
			residual = g_form.getValue(residualField);
			doCheck();
		}

		function setInherent(criteria) {
			if(criteria.type == 'likelihood')
				inherent = criteria.percentage_max_value;
			else 
				inherent = parseInt(criteria.currency_max_value);
			doCheck();
		}

		function setResidual(criteria) {
			if(criteria.type == 'likelihood')
				residual = criteria.percentage_max_value;
			else
				residual = parseInt(criteria.currency_max_value);	
			doCheck();
		}

		function doCheck() {
			if(inherent !== false && residual !== false && (parseFloat(residual)) > parseFloat(inherent)) {
				switch(fieldType) {
					case 'likelihood' :
						g_form.showErrorBox(inherentField,getMessage('sn_risk_likelihood_inherent_lower_than_residual'));
						break;
					case 'residual_likelihood' :
						g_form.showErrorBox(residualField,getMessage('sn_risk_likelihood_residual_higher_than_inherent'));
						break;
					case 'impact' :
						g_form.showErrorBox(inherentField,getMessage('sn_risk_impact_inherent_lower_than_residual'));
						break;
					case 'residual_impact' :
						g_form.showErrorBox(residualField,getMessage('sn_risk_impact_residual_higher_than_inherent'));
						break;
					case 'inherent_sle' : 
						g_form.showErrorBox('inherent_sle', getMessage('sn_risk_sle_inherent_lower_than_residual'));
						break;
					case 'default_inherent_sle' :
						g_form.showErrorBox('default_inherent_sle', getMessage('sn_risk_sle_inherent_lower_than_residual'));
						break;
					case 'residual_sle' : 
						g_form.showErrorBox('residual_sle', getMessage('sn_risk_sle_residual_higher_than_inherent'));
						break;
					case 'default_residual_sle' : 
						g_form.showErrorBox('default_residual_sle', getMessage('sn_risk_sle_residual_higher_than_inherent'));
						break;
					case 'inherent_aro' : 
						g_form.showErrorBox('inherent_aro', getMessage('sn_risk_aro_inherent_lower_than_residual'));
						break;
					case 'default_inherent_aro' : 
						g_form.showErrorBox('default_inherent_aro', getMessage('sn_risk_aro_inherent_lower_than_residual'));
						break;
					case 'residual_aro' : 
						g_form.showErrorBox('residual_aro', getMessage('sn_risk_aro_residual_higher_than_inherent'));
						break;
					case 'default_residual_aro' : 
						g_form.showErrorBox('default_residual_aro', getMessage('sn_risk_aro_residual_higher_than_inherent'));
						break;
				}
				return false;
			}
			else
				return true;
		}
	},

	type: 'WR_RiskFormUtilsV2'
};
})();
  • Click on Save button to save the change.

Step 7: Edit Custom Risk Overview dashboard

Go to Service Portal > Page > Click New

  • Search for Custom Risk Overview dashboard.
  • In the "Current Scoring" tab search for widget current and add to the dashboard.
  • Adapt the dashboard according to your taste.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment