Created
April 2, 2020 12:46
-
-
Save sujaykundu777/5d9dfd4bb41810d4d645cba7fda260d0 to your computer and use it in GitHub Desktop.
budget-spi
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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