From b3adf2c64c070ed2d2940e1e99e97d88ea8763c0 Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia Date: Fri, 19 Nov 2010 15:32:48 +0100 Subject: [PATCH] Create CriticalPathProgress object, for storing critical path progress Stores critical path progress duration (by days and by numHours) for a TaskRoot element FEA: ItEr63OTS07ReporteAvancesCadeaCritica --- .../entities/CriticalPathProgress.java | 101 ++++++++++++++ .../business/planner/entities/TaskGroup.java | 25 ++++ .../business/planner/entities/Tasks.hbm.xml | 16 +++ .../web/planner/order/OrderPlanningModel.java | 22 +++- .../web/planner/order/SaveCommand.java | 124 +++++++++--------- 5 files changed, 220 insertions(+), 68 deletions(-) create mode 100644 navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/CriticalPathProgress.java diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/CriticalPathProgress.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/CriticalPathProgress.java new file mode 100644 index 000000000..2b14e49e6 --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/CriticalPathProgress.java @@ -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 . + */ + +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 + * + */ +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 criticalPath) { + byDuration = calculateByDuration(criticalPath); + byNumHours = calculateByNumHours(criticalPath); + } + + private BigDecimal calculateByDuration(List 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 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); + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java index 046e207ad..e3051099e 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/TaskGroup.java @@ -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 criticalPath) { + Validate.isTrue(getParent() == null); + if (criticalPathProgress == null) { + criticalPathProgress = CriticalPathProgress.create(this); + } + criticalPathProgress.update(criticalPath); + } + } diff --git a/navalplanner-business/src/main/resources/org/navalplanner/business/planner/entities/Tasks.hbm.xml b/navalplanner-business/src/main/resources/org/navalplanner/business/planner/entities/Tasks.hbm.xml index e40fdb0c9..eeb6f517d 100644 --- a/navalplanner-business/src/main/resources/org/navalplanner/business/planner/entities/Tasks.hbm.xml +++ b/navalplanner-business/src/main/resources/org/navalplanner/business/planner/entities/Tasks.hbm.xml @@ -96,6 +96,8 @@ + + @@ -118,6 +120,20 @@ + + + + + + rootTask + + + + + + + diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java index 18bb9ef80..a104b8ebd 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/OrderPlanningModel.java @@ -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 configuration, - ISaveCommand saveCommand) { + private void setupOverallProgress(Tabbox chartComponent, Planner planner, PlannerConfiguration 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"); diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java index cddc748a6..bebaa9b00 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/order/SaveCommand.java @@ -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 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() { - @Override - public Boolean execute() { + @Override + public Boolean execute() { - consolidationDAO.reattach(consolidation); - if (consolidation instanceof CalculatedConsolidation) { - SortedSet consolidatedValues = ((CalculatedConsolidation) consolidation) - .getCalculatedConsolidatedValues(); - return consolidatedValues.isEmpty(); - } - if (consolidation instanceof NonCalculatedConsolidation) { - SortedSet consolidatedValues = ((NonCalculatedConsolidation) consolidation) - .getNonCalculatedConsolidatedValues(); - return consolidatedValues.isEmpty(); - } - return false; + consolidationDAO.reattach(consolidation); + if (consolidation instanceof CalculatedConsolidation) { + SortedSet consolidatedValues = ((CalculatedConsolidation) consolidation) + .getCalculatedConsolidatedValues(); + return consolidatedValues.isEmpty(); + } + if (consolidation instanceof NonCalculatedConsolidation) { + SortedSet 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> resourceAllocations = taskElement.getSatisfiedResourceAllocations(); + Set> 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> allocations = t.getLimitingResourceAllocations(); + Set> 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);