Create CriticalPathProgress object, for storing critical path progress
Stores critical path progress duration (by days and by numHours) for a TaskRoot element FEA: ItEr63OTS07ReporteAvancesCadeaCritica
This commit is contained in:
parent
69083ab87e
commit
b3adf2c64c
5 changed files with 220 additions and 68 deletions
|
|
@ -0,0 +1,101 @@
|
|||
/*
|
||||
* This file is part of NavalPlan
|
||||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.navalplanner.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.navalplanner.business.common.BaseEntity;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Diego Pino García<dpino@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class CriticalPathProgress extends BaseEntity {
|
||||
|
||||
public static CriticalPathProgress create(TaskGroup rootTask) {
|
||||
return new CriticalPathProgress(rootTask);
|
||||
}
|
||||
|
||||
private TaskGroup rootTask;
|
||||
|
||||
private BigDecimal byDuration;
|
||||
|
||||
private BigDecimal byNumHours;
|
||||
|
||||
protected CriticalPathProgress() {
|
||||
|
||||
}
|
||||
|
||||
public BigDecimal getByDuration() {
|
||||
return byDuration;
|
||||
}
|
||||
|
||||
public BigDecimal getByNumHours() {
|
||||
return byNumHours;
|
||||
}
|
||||
|
||||
private CriticalPathProgress(TaskGroup rootTask) {
|
||||
this.rootTask = rootTask;
|
||||
}
|
||||
|
||||
public void update(List<Task> criticalPath) {
|
||||
byDuration = calculateByDuration(criticalPath);
|
||||
byNumHours = calculateByNumHours(criticalPath);
|
||||
}
|
||||
|
||||
private BigDecimal calculateByDuration(List<Task> criticalPath) {
|
||||
Integer totalDuration = new Integer(0), duration;
|
||||
BigDecimal totalProgress = BigDecimal.ZERO, progress;
|
||||
|
||||
for (Task each: criticalPath) {
|
||||
duration = each.getWorkableDays();
|
||||
progress = each.getAdvancePercentage();
|
||||
progress = progress.multiply(BigDecimal.valueOf(duration));
|
||||
|
||||
totalDuration = totalDuration + duration;
|
||||
totalProgress = totalProgress.add(progress);
|
||||
}
|
||||
return totalProgress.divide(BigDecimal.valueOf(totalDuration), 8,
|
||||
BigDecimal.ROUND_HALF_EVEN);
|
||||
}
|
||||
|
||||
private BigDecimal calculateByNumHours(List<Task> criticalPath) {
|
||||
int totalNumHours = 0, numHours;
|
||||
BigDecimal totalProgress = BigDecimal.ZERO, progress;
|
||||
|
||||
for (Task each: criticalPath) {
|
||||
numHours = each.getAssignedHours();
|
||||
if (numHours == 0) {
|
||||
numHours = each.getTotalHours();
|
||||
}
|
||||
progress = each.getAdvancePercentage();
|
||||
progress = progress.multiply(BigDecimal.valueOf(numHours));
|
||||
|
||||
totalNumHours += numHours;
|
||||
totalProgress = totalProgress.add(progress);
|
||||
}
|
||||
return totalProgress.divide(BigDecimal.valueOf(totalNumHours), 8,
|
||||
BigDecimal.ROUND_HALF_EVEN);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
package org.navalplanner.business.planner.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
|
@ -55,6 +56,22 @@ public class TaskGroup extends TaskElement {
|
|||
|
||||
}
|
||||
|
||||
private CriticalPathProgress criticalPathProgress;
|
||||
|
||||
public BigDecimal getCriticalPathProgressByDuration() {
|
||||
if (criticalPathProgress == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return criticalPathProgress.getByDuration();
|
||||
}
|
||||
|
||||
public BigDecimal getCriticalPathProgressByNumHours() {
|
||||
if (criticalPathProgress == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return criticalPathProgress.getByNumHours();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@AssertTrue(message = "order element associated to a task group must be not null")
|
||||
private boolean theOrderElementMustBeNotNull() {
|
||||
|
|
@ -215,4 +232,12 @@ public class TaskGroup extends TaskElement {
|
|||
return result;
|
||||
}
|
||||
|
||||
public void updateCriticalPathProgress(List<Task> criticalPath) {
|
||||
Validate.isTrue(getParent() == null);
|
||||
if (criticalPathProgress == null) {
|
||||
criticalPathProgress = CriticalPathProgress.create(this);
|
||||
}
|
||||
criticalPathProgress.update(criticalPath);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@
|
|||
<joined-subclass name="TaskGroup">
|
||||
<key column="TASK_ELEMENT_ID"></key>
|
||||
|
||||
<one-to-one name="criticalPathProgress" class="CriticalPathProgress" cascade="all" />
|
||||
|
||||
<!-- Indexed on the other side -->
|
||||
<list name="taskElements" cascade="all">
|
||||
<key column="parent" not-null="false"></key>
|
||||
|
|
@ -118,6 +120,20 @@
|
|||
</joined-subclass>
|
||||
|
||||
</class>
|
||||
|
||||
<!-- CriticalPathProgress -->
|
||||
<class name="CriticalPathProgress" table="CRITICAL_PATH_PROGRESS">
|
||||
<id name="id" column="CRITICAL_PATH_PROGRESS_ID">
|
||||
<generator class="foreign">
|
||||
<param name="property">rootTask</param>
|
||||
</generator>
|
||||
</id>
|
||||
<one-to-one name="rootTask" class="TaskGroup" constrained="true"
|
||||
cascade="all" lazy="false" />
|
||||
<property name="byDuration" column="BY_DURATION" />
|
||||
<property name="byNumHours" column="BY_NUM_HOURS" />
|
||||
</class>
|
||||
|
||||
<class name="Dependency">
|
||||
<id name="id" type="long" access="property">
|
||||
<generator class="hilo"></generator>
|
||||
|
|
|
|||
|
|
@ -395,8 +395,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
|
|||
|
||||
setupLoadChart(chartLoadTimeplot, planner, configuration, saveCommand);
|
||||
setupEarnedValueChart(chartEarnedValueTimeplot, earnedValueChartFiller, planner, configuration, saveCommand);
|
||||
ProgressType progressType = configurationDAO.getConfiguration().getProgressType();
|
||||
setupOverallProgress(chartComponent, progressType, planner, configuration, saveCommand);
|
||||
setupOverallProgress(chartComponent, planner, configuration, saveCommand);
|
||||
|
||||
planner.addGraphChangeListenersFromConfiguration(configuration);
|
||||
}
|
||||
|
|
@ -510,9 +509,18 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
|
|||
setEventListenerConfigurationCheckboxes(earnedValueChart);
|
||||
}
|
||||
|
||||
private void setupOverallProgress(Tabbox chartComponent,
|
||||
final ProgressType progressType, Planner planner, PlannerConfiguration<TaskElement> configuration,
|
||||
ISaveCommand saveCommand) {
|
||||
private void setupOverallProgress(Tabbox chartComponent, Planner planner, PlannerConfiguration<TaskElement> configuration,
|
||||
final ISaveCommand saveCommand) {
|
||||
|
||||
saveCommand.addListener(new IAfterSaveListener() {
|
||||
@Override
|
||||
public void onAfterSave() {
|
||||
// FIXME: Should create overallProgressContent if it's null
|
||||
if (overallProgressContent != null) {
|
||||
overallProgressContent.update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chartComponent.addEventListener(Events.ON_SELECT, new EventListener() {
|
||||
|
||||
|
|
@ -523,7 +531,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
|
|||
if (isOverAllProgressSelected(selectedTab)) {
|
||||
if (overallProgressContent == null) {
|
||||
final Tabpanel tabpanel = getSelectedPanel(selectedTab);
|
||||
overallProgressContent = new OverAllProgressContent(tabpanel, progressType);
|
||||
overallProgressContent = new OverAllProgressContent(tabpanel);
|
||||
}
|
||||
overallProgressContent.update();
|
||||
}
|
||||
|
|
@ -1553,7 +1561,7 @@ public abstract class OrderPlanningModel implements IOrderPlanningModel {
|
|||
private Label lbAdvancePercentage;
|
||||
|
||||
|
||||
public OverAllProgressContent(Tabpanel tabpanel, ProgressType progressType) {
|
||||
public OverAllProgressContent(Tabpanel tabpanel) {
|
||||
progressCriticalPathByDuration = (Progressmeter) tabpanel.getFellowIfAny("progressCriticalPathByDuration");
|
||||
lbCriticalPathByDuration = (Label) tabpanel.getFellowIfAny("lbCriticalPathByDuration");
|
||||
progressCriticalPathByNumHours = (Progressmeter) tabpanel.getFellowIfAny("progressCriticalPathByNumHours");
|
||||
|
|
|
|||
|
|
@ -148,8 +148,8 @@ public class SaveCommand implements ISaveCommand {
|
|||
|
||||
private void notifyUserThatSavingIsDone() {
|
||||
try {
|
||||
Messagebox.show(_("Scheduling saved"), _("Information"), Messagebox.OK,
|
||||
Messagebox.INFORMATION);
|
||||
Messagebox.show(_("Scheduling saved"), _("Information"),
|
||||
Messagebox.OK, Messagebox.INFORMATION);
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
@ -193,18 +193,18 @@ public class SaveCommand implements ISaveCommand {
|
|||
}
|
||||
|
||||
private void saveRootTaskIfNecessary() {
|
||||
TaskGroup rootTask = state.getRootTask();
|
||||
if (!state.getTasksToSave().isEmpty()) {
|
||||
TaskGroup rootTask = state.getRootTask();
|
||||
|
||||
updateRootTaskPosition(rootTask);
|
||||
updateCriticalPathProgress(rootTask);
|
||||
taskElementDAO.save(rootTask);
|
||||
}
|
||||
updateCriticalPathProgress(rootTask);
|
||||
taskElementDAO.save(rootTask);
|
||||
}
|
||||
|
||||
private void updateCriticalPathProgress(TaskGroup rootTask) {
|
||||
List criticalPath = state.getPlanner().getCriticalPath();
|
||||
BigDecimal byDuration = CriticalPathProgress.calculateByDuration(criticalPath);
|
||||
System.out.println("### updateCriticalPathProgress: " + byDuration);
|
||||
final List<Task> criticalPath = state.getPlanner().getCriticalPath();
|
||||
rootTask.updateCriticalPathProgress(criticalPath);
|
||||
}
|
||||
|
||||
private void updateRootTaskPosition(TaskGroup rootTask) {
|
||||
|
|
@ -243,10 +243,9 @@ public class SaveCommand implements ISaveCommand {
|
|||
private void updateLimitingResourceQueueElementDates(Task task) {
|
||||
LimitingResourceQueueElement limiting = task
|
||||
.getAssociatedLimitingResourceQueueElementIfAny();
|
||||
Date initDate = state
|
||||
.getRootTask().getOrderElement().getInitDate();
|
||||
limiting.updateDates(initDate, task
|
||||
.getDependenciesWithThisDestination());
|
||||
Date initDate = state.getRootTask().getOrderElement().getInitDate();
|
||||
limiting.updateDates(initDate,
|
||||
task.getDependenciesWithThisDestination());
|
||||
}
|
||||
|
||||
private void removeEmptyConsolidation(TaskElement taskElement) {
|
||||
|
|
@ -270,24 +269,24 @@ public class SaveCommand implements ISaveCommand {
|
|||
private boolean isEmptyConsolidation(final Consolidation consolidation) {
|
||||
return transactionService
|
||||
.runOnTransaction(new IOnTransaction<Boolean>() {
|
||||
@Override
|
||||
public Boolean execute() {
|
||||
@Override
|
||||
public Boolean execute() {
|
||||
|
||||
consolidationDAO.reattach(consolidation);
|
||||
if (consolidation instanceof CalculatedConsolidation) {
|
||||
SortedSet<CalculatedConsolidatedValue> consolidatedValues = ((CalculatedConsolidation) consolidation)
|
||||
.getCalculatedConsolidatedValues();
|
||||
return consolidatedValues.isEmpty();
|
||||
}
|
||||
if (consolidation instanceof NonCalculatedConsolidation) {
|
||||
SortedSet<NonCalculatedConsolidatedValue> consolidatedValues = ((NonCalculatedConsolidation) consolidation)
|
||||
.getNonCalculatedConsolidatedValues();
|
||||
return consolidatedValues.isEmpty();
|
||||
}
|
||||
return false;
|
||||
consolidationDAO.reattach(consolidation);
|
||||
if (consolidation instanceof CalculatedConsolidation) {
|
||||
SortedSet<CalculatedConsolidatedValue> consolidatedValues = ((CalculatedConsolidation) consolidation)
|
||||
.getCalculatedConsolidatedValues();
|
||||
return consolidatedValues.isEmpty();
|
||||
}
|
||||
if (consolidation instanceof NonCalculatedConsolidation) {
|
||||
SortedSet<NonCalculatedConsolidatedValue> consolidatedValues = ((NonCalculatedConsolidation) consolidation)
|
||||
.getNonCalculatedConsolidatedValues();
|
||||
return consolidatedValues.isEmpty();
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// newly added TaskElement such as milestones must be called
|
||||
|
|
@ -298,7 +297,8 @@ public class SaveCommand implements ISaveCommand {
|
|||
}
|
||||
dontPoseAsTransient(taskElement.getDependenciesWithThisOrigin());
|
||||
dontPoseAsTransient(taskElement.getDependenciesWithThisDestination());
|
||||
Set<ResourceAllocation<?>> resourceAllocations = taskElement.getSatisfiedResourceAllocations();
|
||||
Set<ResourceAllocation<?>> resourceAllocations = taskElement
|
||||
.getSatisfiedResourceAllocations();
|
||||
dontPoseAsTransientAndChildrenObjects(resourceAllocations);
|
||||
if (!taskElement.isLeaf()) {
|
||||
for (TaskElement each : taskElement.getChildren()) {
|
||||
|
|
@ -320,19 +320,19 @@ public class SaveCommand implements ISaveCommand {
|
|||
|
||||
private void updateLimitingQueueDependencies(Task t) {
|
||||
|
||||
for (Dependency each: t.getDependenciesWithThisOrigin()) {
|
||||
for (Dependency each : t.getDependenciesWithThisOrigin()) {
|
||||
addLimitingDependencyIfNeeded(each);
|
||||
removeLimitingDependencyIfNeeded(each);
|
||||
}
|
||||
}
|
||||
|
||||
private void addLimitingDependencyIfNeeded(Dependency d) {
|
||||
if (d.isDependencyBetweenLimitedAllocatedTasks() &&
|
||||
!d.hasLimitedQueueDependencyAssociated()) {
|
||||
LimitingResourceQueueElement origin =
|
||||
calculateQueueElementFromDependency((Task) d.getOrigin());
|
||||
LimitingResourceQueueElement destiny =
|
||||
calculateQueueElementFromDependency((Task) d.getDestination());
|
||||
if (d.isDependencyBetweenLimitedAllocatedTasks()
|
||||
&& !d.hasLimitedQueueDependencyAssociated()) {
|
||||
LimitingResourceQueueElement origin = calculateQueueElementFromDependency((Task) d
|
||||
.getOrigin());
|
||||
LimitingResourceQueueElement destiny = calculateQueueElementFromDependency((Task) d
|
||||
.getDestination());
|
||||
|
||||
LimitingResourceQueueDependency queueDependency = LimitingResourceQueueDependency
|
||||
.create(origin, destiny, d,
|
||||
|
|
@ -343,20 +343,21 @@ public class SaveCommand implements ISaveCommand {
|
|||
}
|
||||
}
|
||||
|
||||
private LimitingResourceQueueElement
|
||||
calculateQueueElementFromDependency(Task t) {
|
||||
private LimitingResourceQueueElement calculateQueueElementFromDependency(
|
||||
Task t) {
|
||||
|
||||
LimitingResourceQueueElement result = null;
|
||||
// TODO: Improve this method: One Task can only have one
|
||||
// limiting resource allocation
|
||||
Set<ResourceAllocation<?>> allocations = t.getLimitingResourceAllocations();
|
||||
Set<ResourceAllocation<?>> allocations = t
|
||||
.getLimitingResourceAllocations();
|
||||
|
||||
if (allocations.isEmpty() || allocations.size() != 1) {
|
||||
throw new ValidationException("Incorrect limiting resource " +
|
||||
"allocation configuration");
|
||||
throw new ValidationException("Incorrect limiting resource "
|
||||
+ "allocation configuration");
|
||||
}
|
||||
|
||||
for (ResourceAllocation<?> r: allocations) {
|
||||
for (ResourceAllocation<?> r : allocations) {
|
||||
result = r.getLimitingResourceQueueElement();
|
||||
}
|
||||
|
||||
|
|
@ -364,22 +365,22 @@ public class SaveCommand implements ISaveCommand {
|
|||
}
|
||||
|
||||
private void removeLimitingDependencyIfNeeded(Dependency d) {
|
||||
if (!d.isDependencyBetweenLimitedAllocatedTasks() &&
|
||||
(d.hasLimitedQueueDependencyAssociated())) {
|
||||
LimitingResourceQueueDependency queueDependency =
|
||||
d.getQueueDependency();
|
||||
queueDependency.getHasAsOrigin().remove(queueDependency);
|
||||
queueDependency.getHasAsDestiny().remove(queueDependency);
|
||||
d.setQueueDependency(null);
|
||||
try {
|
||||
limitingResourceQueueDependencyDAO.
|
||||
remove(queueDependency.getId());
|
||||
} catch (InstanceNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Trying to delete instance " +
|
||||
" does not exist");
|
||||
}
|
||||
if (!d.isDependencyBetweenLimitedAllocatedTasks()
|
||||
&& (d.hasLimitedQueueDependencyAssociated())) {
|
||||
LimitingResourceQueueDependency queueDependency = d
|
||||
.getQueueDependency();
|
||||
queueDependency.getHasAsOrigin().remove(queueDependency);
|
||||
queueDependency.getHasAsDestiny().remove(queueDependency);
|
||||
d.setQueueDependency(null);
|
||||
try {
|
||||
limitingResourceQueueDependencyDAO.remove(queueDependency
|
||||
.getId());
|
||||
} catch (InstanceNotFoundException e) {
|
||||
e.printStackTrace();
|
||||
throw new RuntimeException("Trying to delete instance "
|
||||
+ " does not exist");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dontPoseAsTransient(OrderElement orderElement) {
|
||||
|
|
@ -468,10 +469,12 @@ public class SaveCommand implements ISaveCommand {
|
|||
|
||||
private static void dontPoseAsTransient(LimitingResourceQueueElement element) {
|
||||
if (element != null) {
|
||||
for (LimitingResourceQueueDependency d: element.getDependenciesAsOrigin()) {
|
||||
for (LimitingResourceQueueDependency d : element
|
||||
.getDependenciesAsOrigin()) {
|
||||
d.dontPoseAsTransientObjectAnymore();
|
||||
}
|
||||
for (LimitingResourceQueueDependency d: element.getDependenciesAsDestiny()) {
|
||||
for (LimitingResourceQueueDependency d : element
|
||||
.getDependenciesAsDestiny()) {
|
||||
d.dontPoseAsTransientObjectAnymore();
|
||||
}
|
||||
element.dontPoseAsTransientObjectAnymore();
|
||||
|
|
@ -538,8 +541,7 @@ public class SaveCommand implements ISaveCommand {
|
|||
private boolean userAcceptsCreateANewOrderVersion() {
|
||||
try {
|
||||
int status = Messagebox
|
||||
.show(
|
||||
_("Confirm creating a new order version for this scenario and derived. Are you sure?"),
|
||||
.show(_("Confirm creating a new order version for this scenario and derived. Are you sure?"),
|
||||
_("New order version"), Messagebox.OK
|
||||
| Messagebox.CANCEL, Messagebox.QUESTION);
|
||||
return (Messagebox.OK == status);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue