Skip to content

Instantly share code, notes, and snippets.

@sujaykundu777
Created April 2, 2020 12:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sujaykundu777/5d9dfd4bb41810d4d645cba7fda260d0 to your computer and use it in GitHub Desktop.
Save sujaykundu777/5d9dfd4bb41810d4d645cba7fda260d0 to your computer and use it in GitHub Desktop.
budget-spi
const { ProjectTaskRepository } = require('../../repository/project-task')
const { CalendarRepository } = require('../../repository/calendars');
const { ProjectSchedulerBudgetRepository } = require("../../repository/project-scheduler-budget");
const error = require("../action-helper/common-error");
const throwError = error.throwError;
const moment = require('moment');
class GetEarnedValueofTask {
constructor(project_id) {
this.project_id = project_id;
}
// to get dates list between two dates
async getDateArray(start, end){
let arr = new Array();
let dt = new Date(start);
while (dt <= end) {
arr.push(new Date(dt));
dt.setDate(dt.getDate() + 1);
}
return arr;
}
async execute() {
try {
let projectTaskRepository = new ProjectTaskRepository();
let calendarRepo = new CalendarRepository();
let allocatedBudgetRepo = new ProjectSchedulerBudgetRepository();
let [allTasks, totalAllocatedValue] = await Promise.all([
projectTaskRepository.getTaskDetailsBasedOnTaskId(this.project_id),
allocatedBudgetRepo.getTotalAllocatedBudgetLineItem(this.project_id)
]);
// if Total budget allocated in a project is 0, then show "N/a" for Earned Value, SPI and Scheduled Value fields of the task board
if ( totalAllocatedValue[0] === undefined ) {
let result = {
"earned_value": "N/A",
"BCWS": "N/A",
"SPI": "N/A"
}
return result
}
let earnedValue = 0;
let budgetedCost = 0;
for(let taskDetails of allTasks){
// for(let i=0, length= allTasks.length; i<length; i++){
if(taskDetails.task_id !== this.project_id){
let projectCalender = await calendarRepo.getCalendarByDocId(taskDetails.calendar_id)
let working_days = projectCalender.working_days;
let calendarHolidays = projectCalender.holidays;
// to get non working days
let nonworking_days = [];
Object.keys(working_days).forEach( function(key) {
working_days[key] === 0 ? nonworking_days.push(key) : false;
});
// to get holidays list
let holidayList = []
for(let holiday of calendarHolidays){
holidayList.push(new Date(holiday.date));
}
// let taskDetails = allTasks[i]
if(taskDetails.task_id !== this.project_id){
let duration = taskDetails.duration;
let taskProgress = taskDetails.progress;
let costAssigned = 0;
if(taskDetails.budget_line_items && taskDetails.budget_line_items > 0 ){
for(let i=0; i<taskDetails.budget_line_items.length; i++){
costAssigned = costAssigned + taskDetails.budget_line_items[i].total_allocated;
}
}
// EV = Updated progress percentage * Costs assigned to the Task
let taskLevelEarnedValue = (taskProgress/100) * costAssigned;
earnedValue = earnedValue + taskLevelEarnedValue;
// Days Elapsed = Today's Date - Planned Start Date (If result is positive else 0)
let plannedStartDate = taskDetails.planned_start_date;
// to get dates list between planned start date and current date
let startDate = moment(plannedStartDate);
let endDate = moment().subtract(1, 'day')
let dateList = await this.getDateArray(startDate, endDate);
let dateCount = 0;
for(let dates of dateList){
if (!(holidayList.includes(dates)) && !(nonworking_days.includes(moment(dates).format('dddd').toLowerCase()))){
dateCount++;
}
}
let DaysElapsed = dateCount > duration ? duration : dateCount;
// Expected Progress of a task = Days Elapsed / Total duration
let expectedProgress = DaysElapsed/duration;
expectedProgress = (taskDetails.task_type === 'Milestone' && duration === 0 ) ? 0 : expectedProgress;
// BCWS = Expected progress percentage * Costs assigned to the Task
let taskLevelBudgetedCost = expectedProgress * costAssigned;
budgetedCost = budgetedCost + taskLevelBudgetedCost;
}
}
}
// In a case where Total SV or BCWS for a project is 0, then show the SPI as 100%
if( budgetedCost === 0 ){
let result = {
"earned_value": Number(earnedValue.toFixed(2)),
"BCWS": Number(budgetedCost.toFixed(2)),
"SPI": 1
}
return result
}
// SPI = EV/BCWS
let SPI = earnedValue/budgetedCost;
SPI = budgetedCost === 0 ? 0 : Number(SPI.toFixed(2));
let resultObject = {
"earned_value": Number(earnedValue.toFixed(2)),
"BCWS": Number(budgetedCost.toFixed(2)),
"SPI": SPI
}
return resultObject;
}
catch (error) {
throw error;
}
}
}
exports.GetEarnedValueofTask = GetEarnedValueofTask;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment