use of teamdash.wbs.WBSSynchronizer.ActualSubtaskData in project processdash by dtuma.
the class TeamActualTimeColumn method recalculate.
/** Recalculate data for a single node in the WBS.
*
* With a single pass over the WBS, this method calculates actual time
* for each team member and for the entire team; actual earned value,
* completion date, percent complete, and percent spent.
*
* @param node the node to recalculate
* @param actualTime a result array, having one entry for each member of the
* team project. This method should calculate (for each team member)
* the total actual time for this node and all children, and store the
* resulting value in corresponding field of this array.
* @param earnedValue a single-entry result array. This method should
* calculate the team earned value (for this node and all children,
* in hours), and return the result in the single field of this array.
* @param completionDate a single-entry result array. This method should
* calculate the actual completion date of this node and all children,
* and return the result in the single field of this array.
*/
private void recalculate(WBSNode node, double[] actualTime, TimeCalculator[] timeCalc, double[] earnedValue, long[] completionDate) {
// get the list of children underneath this node
WBSNode[] children = wbsModel.getChildren(node);
boolean isLeaf = (children.length == 0);
// load the actual node time for each individual into our working array
for (int i = 0; i < teamSize; i++) actualTime[i] = nanToZero(node.getNumericAttribute(nodeTimeAttrs[i]));
earnedValue[0] = 0;
completionDate[0] = COMPL_DATE_NA;
if (isLeaf) {
int milestone = MilestoneColumn.getMilestoneID(node);
// accumulate EV and completion date information for this leaf
for (int i = 0; i < teamSize; i++) {
// decide whether data from this team member should be included
// in team sums
boolean rollupMember = rollupEveryone || matchesTeamFilter[i];
// retrieve the planned time for one team member.
double memberPlanTime = nanToZero(node.getNumericAttribute(planTimeAttrs[i]));
boolean assignedWithZero = (node.getAttribute(assignedWithZeroAttrs[i]) != null);
if (memberPlanTime > 0 || assignedWithZero) {
// if this team member is assigned to this leaf task, get
// their actual completion date for the task.
Date memberCompletionDate = (Date) node.getAttribute(completionDateAttrs[i]);
// keep track of the max completion date so far.
if (rollupMember)
completionDate[0] = mergeCompletionDate(completionDate[0], memberCompletionDate);
// team has earned the value associated with the task.
if (memberCompletionDate != null) {
if (rollupMember)
earnedValue[0] += memberPlanTime;
timeCalc[i].addCompletedTask(memberPlanTime, actualTime[i], milestone);
} else {
// See if subtask data is present for this task
List<ActualSubtaskData> subtaskData = (List) node.getAttribute(subtaskDataAttrs[i]);
if (subtaskData != null && !subtaskData.isEmpty()) {
// if subtask data is present, handle it.
// if the time estimate in the personal dashboard is
// out of sync with the WBS, the subtask times will
// add up to a different value than memberPlanTime.
// calculate this ratio so we can adjust EV.
double subtaskPlanTotal = 0;
for (ActualSubtaskData subtask : subtaskData) subtaskPlanTotal += subtask.getPlanTime();
double ratio = memberPlanTime / subtaskPlanTotal;
if (Double.isInfinite(ratio) || Double.isNaN(ratio))
ratio = 0;
// record each subtask as an independent task.
for (ActualSubtaskData subtask : subtaskData) {
if (subtask.getCompletionDate() != null) {
// this subtask was completed
if (rollupMember)
earnedValue[0] += subtask.getPlanTime() * ratio;
timeCalc[i].addCompletedTask(subtask.getPlanTime(), subtask.getActualTime(), milestone);
} else {
// this subtask is remaining
timeCalc[i].addRemainingTask(subtask.getPlanTime(), subtask.getActualTime(), milestone);
}
}
} else {
// there is no subtask data for this node. Just
// record a plain remaining task.
timeCalc[i].addRemainingTask(memberPlanTime, actualTime[i], milestone);
}
}
}
}
} else {
double[] childTime = new double[teamSize];
double[] childEarnedValue = new double[1];
long[] childCompletionDate = new long[1];
for (int i = 0; i < children.length; i++) {
// ask our child to compute its time data
recalculate(children[i], childTime, timeCalc, childEarnedValue, childCompletionDate);
// if the child isn't hidden, add its values to our totals
if (!children[i].isHidden()) {
// accumulate time from that child into our total
for (int j = 0; j < teamSize; j++) actualTime[j] += childTime[j];
// accumulate EV related data from our children
earnedValue[0] += childEarnedValue[0];
completionDate[0] = Math.max(completionDate[0], childCompletionDate[0]);
}
}
}
double totalActualTime = 0;
for (int i = 0; i < teamSize; i++) {
// add up the actual time for all included team members
if (rollupEveryone || matchesTeamFilter[i])
totalActualTime += actualTime[i];
// also store the total time per individual for this node
node.setNumericAttribute(actTimeAttrs[i], actualTime[i]);
}
// store the actual time for the entire team for this node.
node.setNumericAttribute(ACT_TIME_ATTR_NAME, totalActualTime);
// retrieve the total plan time for this node from the TeamTimeColumn.
double totalPlanTime = nanToZero(NumericDataValue.parse(dataModel.getValueAt(node, teamPlanTimeColumnNum)));
// calculate and store the percent spent
double percentSpent = totalActualTime / totalPlanTime;
node.setNumericAttribute(PercentSpentColumn.RESULT_ATTR, percentSpent);
// calculate and store the completion date and percent complete
Date cd = null;
double percentComplete = earnedValue[0] / totalPlanTime;
if (completionDate[0] != COMPL_DATE_NA && completionDate[0] != INCOMPLETE) {
cd = new Date(completionDate[0]);
percentComplete = 1.0;
}
node.setAttribute(TeamCompletionDateColumn.ATTR_NAME, cd);
node.setNumericAttribute(PercentCompleteColumn.RESULT_ATTR, percentComplete);
}
Aggregations