Name
global.BurndownMetric
Description
This parent utility is used by the burn down charts utilites
Script
var BurndownMetric = Class.create();
BurndownMetric.prototype = {
STORY_METRIC: "RM Story State Capture",
STORY_STATE_WORK_IN_PROGRESS: 2,
STORY_STATE_COMPLETE: 3,
STORY_STATE_PLANNING: 1,
STORY_STATE_CANCELLED: 4,
STORY_STATE_DRAFT: -6,
SCRUM_PP_BURNDOWN_LOG: 'com.snc.sdlc.scrum.pp.burndown.debug',
initialize: function ( burndownRequest ) {
this.burndownRequest = burndownRequest;
this.glideRecord = this.getGlideRecord();
if( this.burndownRequest.view == 'PROJECT') {
var projectRecordDecorator = new ProjectRecordDecorator(this.glideRecord);
var dates = projectRecordDecorator.getSprintsStartEndDate();
if ( dates.startDate )
this.startDate = new GlideDateTime(dates.startDate);
if ( dates.startDate )
this.endDate = new GlideDateTime(dates.endDate);
}
else {
this.startDate = new GlideDateTime( this.glideRecord.getValue('start_date'));
this.endDate = new GlideDateTime( this.glideRecord.getValue('end_date'));
}
this.gsLog = new GSLog(this.SCRUM_PP_BURNDOWN_LOG, this.type);
this.gsLog.setLevel("debug");
this.gsLog.logDebug('BurndownMetric sysId: ' + this.burndownRequest.sysId + ' ;this.view: ' + this.burndownRequest.view + ' ;this.table: ' + this.burndownRequest.table + ' ;this.startDate: ' + this.startDate +
' ;this.endDate: ' + this.endDate + ' ;this.metricDefinition: ' + this.burndownRequest.metricDefinition + ' ;this.metricId: ' + this.burndownRequest.metricId +
' ;this.referenceField: ' + this.burndownRequest.referenceField );
},
getGlideRecord: function() {
if ( !this.glideRecord ) {
var gr = new GlideRecord( this.burndownRequest.table );
gr.get( this.burndownRequest.sysId );
this.glideRecord = gr;
}
return this.glideRecord;
},
getTitle: function() {
var gr = this.getGlideRecord();
return gr.getValue('short_description');
},
getStartDate: function() {
return this.startDate;
},
getEndDate: function() {
return this.endDate;
},
getMetricInstances: function( ) {
var gr = new GlideRecord("metric_instance");
gr.addQuery("definition.name", this.burndownRequest.metricDefinition);
gr.addQuery("id", this.burndownRequest.metricId);
gr.orderBy("start");
gr.query();
return gr;
},
getDailyTotals: function() {
var totals = {};
var grMetrics = this.getMetricInstances();
if (grMetrics.next()) {
totals.startingValue = 0;
do {
if (grMetrics.start.getGlideObject().getDate().compareTo(this.getStartDate()) <= 0)
totals.startingValue = this.clearFormatting(grMetrics.value) - 0;
totals[grMetrics.start.getGlideObject().getLocalDate()] = this.clearFormatting(grMetrics.value) - 0;
/*this.gsLog.logDebug('getDailyTotals[' + grMetrics.start.getGlideObject().getDate() + ']= ' + this.clearFormatting(grMetrics.value) );*/
} while (grMetrics.next());
}
return totals;
},
getDailyTotalsMap: function() {
var data = {};
var startDate = new GlideDateTime(this.getStartDate()).getLocalDate();
var endDate = new GlideDateTime(this.getEndDate()).getLocalDate();
var totals = this.getDailyTotals();
var dailyPointsTotal = totals.startingValue;
while (startDate.compareTo(endDate) <= 0) {
if (JSUtil.nil(totals[startDate])) {
data[startDate] = {
dailyPoints : dailyPointsTotal,
changed : false
};
}
else {
dailyPointsTotal = totals[startDate];
data[startDate] = {
dailyPoints : dailyPointsTotal,
changed : true
};
}
/*this.gsLog.logDebug('getDailyTotalsMap[' + startDate + '] { key: ' + data[startDate]['dailyPoints'] + ' , value: ' + data[startDate]['changed'] + '}');*/
startDate.addDays(1);
}
data.startingValue = totals.startingValue;
return data;
},
getStories: function() {
var stories = {};
var gr = new GlideRecord("rm_story");
gr.addQuery(this.burndownRequest.referenceField, this.burndownRequest.sysId);
gr.query();
while (gr.next()) {
stories[String(gr.sys_id)] = gr.story_points - 0;
}
return stories;
},
getStoryMetricIntances: function( metricIds ) {
gr = new GlideRecord("metric_instance");
gr.addQuery("definition.name", this.STORY_METRIC);
gr.addQuery("id", 'IN', metricIds);
gr.orderBy("start");
gr.query();
return gr;
},
getStoryMetrics: function() {
var startDate = new GlideDateTime(this.getStartDate()).getLocalDate();
var endDate = new GlideDateTime(this.getEndDate()).getLocalDate();
var metrics = {};
var storyCarryOvers = {};
var stories = this.getStories();
var storySysIds = '';
for ( var storySysId in stories ) {
storySysIds += storySysId + ',' ;
}
var gr = this.getStoryMetricIntances(storySysIds);
while (gr.next()) {
var date = gr.start.getGlideObject().getLocalDate();
var value = 0;
if (date.compareTo(startDate) < 0 || date.compareTo(endDate) > 0)
continue;
switch (gr.field_value - 0) {
case this.STORY_STATE_CANCELLED:
if (!storyCarryOvers[String(gr.id)])
storyCarryOvers[String(gr.id)] = this.STORY_STATE_CANCELLED;
value = stories[gr.id] * -1;
break;
case this.STORY_STATE_COMPLETE:
if (!storyCarryOvers[String(gr.id)])
storyCarryOvers[String(gr.id)] = this.STORY_STATE_CANCELLED;
value = stories[gr.id] * -1;
break;
default:
if (storyCarryOvers[String(gr.id)])
value = stories[gr.id];
}
metrics[date] = metrics[date] ? metrics[date] + value : value;
/*this.gsLog.logDebug('getStoryMetrics[' + date + '] : ' + metrics[date] );*/
}
return metrics;
},
getDailyPoints: function() {
var data = [];
var startDate = new GlideDateTime(this.getStartDate()).getLocalDate();
var endDate = new GlideDateTime(this.getEndDate()).getLocalDate();
var dailyTotalMap = this.getDailyTotalsMap();
while (startDate.compareTo(endDate) <= 0) {
data.push({
// key : String(new GlideDateTime(startDate).getDate()),
key : String(startDate),
value : dailyTotalMap[startDate].dailyPoints
});
/*this.gsLog.logDebug('getDailyPoints{key: ' + String(new GlideDateTime(startDate).getDate()) + ', value: ' + dailyTotalMap[startDate].dailyPoints + '}');*/
startDate.addDays(1);
}
return data;
},
getIdeal : function() {
var isIdealLinear = gs.getProperty('com.snc.sdlc.scrum.pp.burndown.ideal.linear', false);
if( isIdealLinear && isIdealLinear == 'true') {
return this.getIdealLinear();
}
else {
return this.getIdealNonLinear();
}
},
getIdealNonLinear: function() {
var data = [];
var startDate = new GlideDateTime(this.getStartDate()).getLocalDate();
var endDate = new GlideDateTime(this.getEndDate()).getLocalDate();
var daysRemaining = (endDate.getNumericValue() - startDate.getNumericValue()) / 1000 / 3600 / 24 + 1;
var dailyTotalsMap = this.getDailyTotalsMap();
var dailyPointsTotal = dailyTotalsMap.startingValue;
var dailyAfterBurnDown = dailyPointsTotal;
var burnDownAmount = dailyPointsTotal / daysRemaining;
while (startDate.compareTo(endDate) <= 0) {
dailyAfterBurnDown += dailyTotalsMap[startDate].dailyPoints - dailyPointsTotal;
dailyPointsTotal = dailyTotalsMap[startDate].dailyPoints;
if (dailyTotalsMap[startDate].changed)
burnDownAmount = dailyAfterBurnDown / daysRemaining;
dailyAfterBurnDown -= burnDownAmount;
daysRemaining--;
data.push({
// key : String(new GlideDateTime(startDate).getDate()),
key : String(startDate),
value : Math.max(dailyAfterBurnDown, 0)
});
/*this.gsLog.logDebug('getIdeal{key: ' + String(new GlideDateTime(startDate).getDate()) + ', value: ' + Math.max(dailyAfterBurnDown, 0) + '}');*/
startDate.addDays(1);
}
return data;
},
hasMetricData: function(){
var gr = this.getMetricInstances();
if (gr.next())
return true;
return false;
},
hasValidDates: function(){
return !this.glideRecord.start_date || !this.glideRecord.end_date ? false : true;
},
getMaxMetricValue: function( ) {
// Value defn a String, cant get MAX as straight
var metricInstances = this.getMetricInstances();
var maxValue = 0;
while( metricInstances.next() ) {
if( parseInt(metricInstances.getValue('value')) > maxValue ) {
maxValue = metricInstances.getValue('value');
}
}
this.gsLog.logDebug('Linear configured, Max Metric Value: ' + maxValue);
return maxValue;
},
getIdealLinear: function() {
var data = [];
var startDate = new GlideDateTime(this.getStartDate()).getLocalDate();
var endDate = new GlideDateTime(this.getEndDate()).getLocalDate();
var daysRemaining = (endDate.getNumericValue() - startDate.getNumericValue()) / 1000 / 3600 / 24 ;
var dailyTotalsMap = this.getDailyTotalsMap();
var dailyPointsTotal = this.getMaxMetricValue();
var dailyAfterBurnDown = dailyPointsTotal;
var burnDownAmount = dailyPointsTotal / daysRemaining;
while (startDate.compareTo(endDate) <= 0) {
data.push({
// key : String(new GlideDateTime(startDate).getDate()),
key : String(startDate),
value : Math.max(dailyAfterBurnDown, 0)
});
dailyAfterBurnDown -= burnDownAmount;
/*this.gsLog.logDebug('getIdealLinear{key: ' + String(new GlideDateTime(startDate).getDate()) + ', value: ' + Math.max(dailyAfterBurnDown, 0) + '}');*/
startDate.addDays(1);
}
return data;
},
clearFormatting: function(value) {
if (value.includes(',')) {
return value.replace(',', '');
}
else if (value.includes('.')) {
return value.replace('.', '');
}
return value;
},
type: 'BurndownMetric'
};
Sys ID
a7c7e0629f022100598a5bb0657fcfb2