From a68efea35b1fc627b6e00cc7de86f265cf5f4ad9 Mon Sep 17 00:00:00 2001 From: Diego Pino Date: Mon, 7 May 2012 12:43:23 +0200 Subject: [PATCH] Code refactoring Create utility class 'CompanyEarnedValueCalculator' for calculating all Earned Value indicators related with Company FEA: ItEr76S15OrganizingPerProjectDashboard --- .../CompanyEarnedValueCalculator.java | 159 ++++++++++++++++++ .../ICompanyEarnedValueCalculator.java | 44 +++++ .../web/planner/chart/ChartFiller.java | 6 + .../planner/chart/EarnedValueChartFiller.java | 6 + .../planner/company/CompanyPlanningModel.java | 112 +++--------- .../web/planner/order/OrderPlanningModel.java | 19 +-- 6 files changed, 245 insertions(+), 101 deletions(-) create mode 100644 libreplan-business/src/main/java/org/libreplan/business/planner/entities/CompanyEarnedValueCalculator.java create mode 100644 libreplan-business/src/main/java/org/libreplan/business/planner/entities/ICompanyEarnedValueCalculator.java diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/entities/CompanyEarnedValueCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/CompanyEarnedValueCalculator.java new file mode 100644 index 000000000..40fdef895 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/CompanyEarnedValueCalculator.java @@ -0,0 +1,159 @@ +/* + * This file is part of LibrePlan + * + * Copyright (C) 2012 Igalia, S.L. + * + * 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.libreplan.business.planner.entities; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; + +import org.joda.time.LocalDate; +import org.libreplan.business.calendars.entities.AvailabilityTimeLine; +import org.libreplan.business.calendars.entities.AvailabilityTimeLine.Interval; +import org.libreplan.business.hibernate.notification.PredefinedDatabaseSnapshots; +import org.libreplan.business.workreports.entities.WorkReportLine; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +/** + * @author Diego Pino García + */ +@Component +@Scope(BeanDefinition.SCOPE_SINGLETON) +public class CompanyEarnedValueCalculator implements ICompanyEarnedValueCalculator { + + @Autowired + private PredefinedDatabaseSnapshots databaseSnapshots; + + @Override + @Transactional(readOnly = true) + public SortedMap calculateBudgetedCostWorkScheduled(AvailabilityTimeLine.Interval interval) { + Map> estimatedCostPerTask = databaseSnapshots + .snapshotEstimatedCostPerTask(); + Collection list = filterTasksByDate( + estimatedCostPerTask.keySet(), interval); + SortedMap estimatedCost = new TreeMap(); + + for (TaskElement each : list) { + addCost(estimatedCost, estimatedCostPerTask.get(each)); + } + return accumulateResult(estimatedCost); + } + + private List filterTasksByDate( + Collection tasks, + AvailabilityTimeLine.Interval interval) { + List result = new ArrayList(); + for(TaskElement task : tasks) { + if (interval.includes(task.getStartAsLocalDate()) + || interval.includes(task.getEndAsLocalDate())) { + result.add(task); + } + } + return result; + } + + private List filterWorkReportLinesByDate( + Collection lines, + AvailabilityTimeLine.Interval interval) { + List result = new ArrayList(); + for(WorkReportLine line: lines) { + if (interval.includes(line.getLocalDate())) { + result.add(line); + } + } + return result; + } + + private void addCost(SortedMap currentCost, + SortedMap additionalCost) { + for (LocalDate day : additionalCost.keySet()) { + if (!currentCost.containsKey(day)) { + currentCost.put(day, BigDecimal.ZERO); + } + currentCost.put(day, currentCost.get(day).add( + additionalCost.get(day))); + } + } + + private SortedMap accumulateResult( + SortedMap map) { + SortedMap result = new TreeMap(); + if (map.isEmpty()) { + return result; + } + + BigDecimal accumulatedResult = BigDecimal.ZERO; + for (LocalDate day : map.keySet()) { + BigDecimal value = map.get(day); + accumulatedResult = accumulatedResult.add(value); + result.put(day, accumulatedResult); + } + + return result; + } + + @Override + public SortedMap calculateActualCostWorkPerformed( + Interval interval) { + SortedMap result = new TreeMap(); + Collection workReportLines = filterWorkReportLinesByDate( + databaseSnapshots.snapshotWorkReportLines(), + interval); + + if (workReportLines.isEmpty()) { + return result; + } + + for (WorkReportLine workReportLine : workReportLines) { + LocalDate day = new LocalDate(workReportLine.getDate()); + BigDecimal cost = workReportLine.getEffort() + .toHoursAsDecimalWithScale(2); + + if (!result.containsKey(day)) { + result.put(day, BigDecimal.ZERO); + } + result.put(day, result.get(day).add(cost)); + } + return accumulateResult(result); + } + + @Override + public SortedMap calculateBudgetedCostWorkPerformed( + Interval interval) { + Map> advanceCostPerTask = databaseSnapshots + .snapshotAdvanceCostPerTask(); + Collection tasks = filterTasksByDate( + advanceCostPerTask.keySet(), interval); + + SortedMap result = new TreeMap(); + for (TaskElement each : tasks) { + addCost(result, advanceCostPerTask.get(each)); + } + return result; + } + +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/entities/ICompanyEarnedValueCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/ICompanyEarnedValueCalculator.java new file mode 100644 index 000000000..9c13eee49 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/ICompanyEarnedValueCalculator.java @@ -0,0 +1,44 @@ +/* + * This file is part of LibrePlan + * + * Copyright (C) 2012 Igalia, S.L. + * + * 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.libreplan.business.planner.entities; + +import java.math.BigDecimal; +import java.util.SortedMap; + +import org.joda.time.LocalDate; +import org.libreplan.business.calendars.entities.AvailabilityTimeLine; + +/** + * @author Diego Pino García + * + * Utility class for calculating all 'Earned Value' measurements + */ +public interface ICompanyEarnedValueCalculator { + + SortedMap calculateBudgetedCostWorkScheduled( + AvailabilityTimeLine.Interval interval); + + SortedMap calculateActualCostWorkPerformed( + AvailabilityTimeLine.Interval interval); + + SortedMap calculateBudgetedCostWorkPerformed( + AvailabilityTimeLine.Interval interval); + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/ChartFiller.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/ChartFiller.java index eaac867bf..bd25935b7 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/ChartFiller.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/ChartFiller.java @@ -508,6 +508,12 @@ public abstract class ChartFiller implements IChartFiller { return result; } + protected SortedMap calculatedValueForEveryDay( + SortedMap values, Interval interval) { + return calculatedValueForEveryDay(values, interval.getStart(), + interval.getFinish()); + } + protected SortedMap calculatedValueForEveryDay( SortedMap map, Date start, Date finish) { return calculatedValueForEveryDay(map, new LocalDate(start), diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java index b4dffbd2d..13e7073c7 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/chart/EarnedValueChartFiller.java @@ -418,4 +418,10 @@ public abstract class EarnedValueChartFiller extends ChartFiller { } } + public void setIndicatorInInterval(EarnedValueType type, + Interval interval, SortedMap values) { + addZeroBeforeTheFirstValue(values); + indicators.put(type, calculatedValueForEveryDay(values, interval)); + } + } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/company/CompanyPlanningModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/company/CompanyPlanningModel.java index eebdf859b..e6bfe65bf 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/company/CompanyPlanningModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/company/CompanyPlanningModel.java @@ -38,8 +38,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.SortedMap; -import java.util.TreeMap; import org.joda.time.LocalDate; import org.libreplan.business.calendars.entities.AvailabilityTimeLine; @@ -55,6 +53,7 @@ import org.libreplan.business.orders.entities.Order; import org.libreplan.business.orders.entities.OrderStatusEnum; import org.libreplan.business.planner.chart.ILoadChartData; import org.libreplan.business.planner.chart.ResourceLoadChartData; +import org.libreplan.business.planner.entities.ICompanyEarnedValueCalculator; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.TaskGroup; import org.libreplan.business.planner.entities.TaskMilestone; @@ -62,7 +61,6 @@ import org.libreplan.business.scenarios.IScenarioManager; import org.libreplan.business.scenarios.entities.Scenario; import org.libreplan.business.users.daos.IUserDAO; import org.libreplan.business.users.entities.User; -import org.libreplan.business.workreports.entities.WorkReportLine; import org.libreplan.web.planner.TaskElementAdapter; import org.libreplan.web.planner.TaskGroupPredicate; import org.libreplan.web.planner.chart.Chart; @@ -132,6 +130,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel { @Autowired private IAdHocTransactionService transactionService; + @Autowired + private ICompanyEarnedValueCalculator earnedValueCalculator; + private List keepAliveZoomListeners = new ArrayList(); private List earnedValueChartConfigurationCheckboxes = new ArrayList(); @@ -275,6 +276,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel { setupChart(chartLoadTimeplot, new CompanyLoadChartFiller(), planner); chartComponent.getTabs().getLastChild().addEventListener(Events.ON_SELECT, new EventListener() { + @Override public void onEvent(Event event) throws Exception { createOnDemandEarnedValueTimePlot(chartComponent, planner); event.getTarget().removeEventListener(Events.ON_SELECT, this); @@ -783,75 +785,33 @@ public class CompanyPlanningModel implements ICompanyPlanningModel { } + /** + * + * @author Manuel Rego Casasnovas + * @author Diego Pino García + * + */ private class CompanyEarnedValueChartFiller extends EarnedValueChartFiller { + @Override protected void calculateBudgetedCostWorkScheduled(Interval interval) { - Map> estimatedCostPerTask = - databaseSnapshots.snapshotEstimatedCostPerTask(); - Collection list = filterTasksByDate( - estimatedCostPerTask.keySet(), getFilterInterval()); - - SortedMap estimatedCost = new TreeMap(); - - for (TaskElement taskElement : list) { - addCost(estimatedCost, estimatedCostPerTask.get(taskElement)); - } - - estimatedCost = accumulateResult(estimatedCost); - addZeroBeforeTheFirstValue(estimatedCost); - indicators.put(EarnedValueType.BCWS, calculatedValueForEveryDay( - estimatedCost, interval.getStart(), interval.getFinish())); + setIndicatorInInterval(EarnedValueType.BCWS, interval, + earnedValueCalculator + .calculateBudgetedCostWorkScheduled(getFilterInterval())); } + @Override protected void calculateActualCostWorkPerformed(Interval interval) { - SortedMap workReportCost = getWorkReportCost(); - - workReportCost = accumulateResult(workReportCost); - addZeroBeforeTheFirstValue(workReportCost); - indicators.put(EarnedValueType.ACWP, calculatedValueForEveryDay( - workReportCost, interval.getStart(), interval.getFinish())); - } - - private SortedMap getWorkReportCost() { - SortedMap result = new TreeMap(); - - Collection workReportLines = filterWorkReportLinesByDate( - databaseSnapshots.snapshotWorkReportLines(), - getFilterInterval()); - - if (workReportLines.isEmpty()) { - return result; - } - - for (WorkReportLine workReportLine : workReportLines) { - LocalDate day = new LocalDate(workReportLine.getDate()); - BigDecimal cost = workReportLine.getEffort() - .toHoursAsDecimalWithScale(2); - - if (!result.containsKey(day)) { - result.put(day, BigDecimal.ZERO); - } - result.put(day, result.get(day).add(cost)); - } - - return result; + setIndicatorInInterval(EarnedValueType.ACWP, interval, + earnedValueCalculator + .calculateActualCostWorkPerformed(getFilterInterval())); } + @Override protected void calculateBudgetedCostWorkPerformed(Interval interval) { - Map> advanceCostPerTask = - databaseSnapshots.snapshotAdvanceCostPerTask(); - Collection list = filterTasksByDate( - advanceCostPerTask.keySet(), getFilterInterval()); - - SortedMap advanceCost = new TreeMap(); - - for (TaskElement taskElement : list) { - addCost(advanceCost, advanceCostPerTask.get(taskElement)); - } - - addZeroBeforeTheFirstValue(advanceCost); - indicators.put(EarnedValueType.BCWP, calculatedValueForEveryDay( - advanceCost, interval.getStart(), interval.getFinish())); + setIndicatorInInterval(EarnedValueType.BCWP, interval, + earnedValueCalculator + .calculateBudgetedCostWorkPerformed(getFilterInterval())); } @Override @@ -859,33 +819,9 @@ public class CompanyPlanningModel implements ICompanyPlanningModel { return getEarnedValueSelectedIndicators(); } - private List filterTasksByDate( - Collection tasks, - AvailabilityTimeLine.Interval interval) { - List result = new ArrayList(); - for(TaskElement task : tasks) { - if (interval.includes(task.getStartAsLocalDate()) - || interval.includes(task.getEndAsLocalDate())) { - result.add(task); - } - } - return result; - } - - - private List filterWorkReportLinesByDate( - Collection lines, - AvailabilityTimeLine.Interval interval) { - List result = new ArrayList(); - for(WorkReportLine line: lines) { - if (interval.includes(line.getLocalDate())) { - result.add(line); - } - } - return result; - } } + @Override @Transactional(readOnly=true) public ProgressType getProgressTypeFromConfiguration() { return configurationDAO.getConfiguration().getProgressType(); diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/OrderPlanningModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/OrderPlanningModel.java index f21c4019f..e6ff9c8a0 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/OrderPlanningModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/planner/order/OrderPlanningModel.java @@ -38,7 +38,6 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.SortedMap; import org.apache.commons.lang.Validate; import org.apache.commons.logging.Log; @@ -1389,6 +1388,12 @@ public class OrderPlanningModel implements IOrderPlanningModel { } + /** + * + * @author Manuel Rego Casasnovas + * @author Diego Pino García + * + */ class OrderEarnedValueChartFiller extends EarnedValueChartFiller { private Order order; @@ -1418,18 +1423,6 @@ public class OrderPlanningModel implements IOrderPlanningModel { .calculateBudgetedCostWorkPerformed(order)); } - private void setIndicatorInInterval(EarnedValueType type, - Interval interval, SortedMap values) { - addZeroBeforeTheFirstValue(values); - indicators.put(type, calculatedValueForEveryDay(values, interval)); - } - - private SortedMap calculatedValueForEveryDay( - SortedMap values, Interval interval) { - return calculatedValueForEveryDay(values, interval.getStart(), - interval.getFinish()); - } - @Override protected Set getSelectedIndicators() { return getEarnedValueSelectedIndicators();