diff --git a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java index b19af9561..d65f6d6ce 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java +++ b/libreplan-business/src/main/java/org/libreplan/business/orders/entities/OrderElement.java @@ -69,6 +69,8 @@ import org.libreplan.business.templates.entities.OrderElementTemplate; import org.libreplan.business.trees.ITreeNode; import org.libreplan.business.util.deepcopy.DeepCopy; import org.libreplan.business.workingday.IntraDayDate; +import org.libreplan.business.workreports.daos.IWorkReportLineDAO; +import org.libreplan.business.workreports.entities.WorkReportLine; public abstract class OrderElement extends IntegrationEntity implements ICriterionRequirable, ITreeNode { @@ -1459,4 +1461,9 @@ public abstract class OrderElement extends IntegrationEntity implements return super.toString() + " :: " + getName(); } + public List getWorkReportLines(boolean sortedByDate) { + IWorkReportLineDAO workReportLineDAO = Registry.getWorkReportLineDAO(); + return workReportLineDAO.findByOrderElementAndChildren(this, sortedByDate); + } + } diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/entities/visitors/CalculateFinishedTasksLagInCompletionVisitor.java b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/visitors/CalculateFinishedTasksLagInCompletionVisitor.java new file mode 100644 index 000000000..3b1ca8dc3 --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/visitors/CalculateFinishedTasksLagInCompletionVisitor.java @@ -0,0 +1,70 @@ +/* + * This file is part of LibrePlan + * + * Copyright (C) 2011 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.visitors; + +/** + * This visitor calculates lastWorkReportDate/EndDate deviation + * for all finished tasks with work report lines attached. + * @author Nacho Barrientos + */ +import java.util.ArrayList; +import java.util.List; + +import org.joda.time.Days; +import org.joda.time.LocalDate; +import org.libreplan.business.planner.entities.Task; +import org.libreplan.business.planner.entities.TaskElement; +import org.libreplan.business.planner.entities.TaskGroup; +import org.libreplan.business.util.TaskElementVisitor; +import org.libreplan.business.workreports.entities.WorkReportLine; + +public class CalculateFinishedTasksLagInCompletionVisitor extends TaskElementVisitor { + + private List deviations; + + public CalculateFinishedTasksLagInCompletionVisitor() { + this.deviations = new ArrayList(); + } + + public List getDeviations() { + return this.deviations; + } + + public void visit(Task task) { + if (task.isFinished()) { + List workReportLines = task. + getOrderElement().getWorkReportLines(true); + if (workReportLines.size() > 0) { + LocalDate lastRLDate = LocalDate.fromDateFields( + workReportLines.get(workReportLines.size()-1).getDate()); + LocalDate endDate = task.getEndAsLocalDate(); + deviations.add((double)Days. + daysBetween(endDate, lastRLDate).getDays()); + } + } + } + + public void visit(TaskGroup taskGroup) { + for (TaskElement each: taskGroup.getChildren()) { + each.acceptVisitor(this); + } + } + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java index f4e9484be..9ce254b65 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/dashboard/DashboardModel.java @@ -22,6 +22,7 @@ package org.libreplan.web.dashboard; import java.math.BigDecimal; import java.math.MathContext; import java.util.ArrayList; +import java.util.Collections; import java.util.EnumMap; import java.util.List; import java.util.Map; @@ -36,6 +37,7 @@ import org.libreplan.business.planner.entities.TaskStatusEnum; import org.libreplan.business.planner.entities.visitors.AccumulateTasksDeadlineStatusVisitor; import org.libreplan.business.planner.entities.visitors.AccumulateTasksStatusVisitor; import org.libreplan.business.planner.entities.visitors.CalculateFinishedTasksEstimationDeviationVisitor; +import org.libreplan.business.planner.entities.visitors.CalculateFinishedTasksLagInCompletionVisitor; import org.libreplan.business.planner.entities.visitors.ResetTasksStatusVisitor; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -52,6 +54,7 @@ public class DashboardModel { public final static int EA_STRETCHES_PERCENTAGE_STEP = 10; public final static int EA_STRETCHES_MIN_VALUE = -100; public final static int EA_STRETCHES_MAX_VALUE = 150; + public final static int LTC_NUMBER_OF_INTERVALS = 10; private Order currentOrder; private Integer taskCount = null; @@ -60,6 +63,7 @@ public class DashboardModel { private Map taskDeadlineViolationStatusStats; private List taskEstimationAccuracyHistogram; private BigDecimal marginWithDeadLine; + private List lagInTaskCompletionHistogram; public DashboardModel() { taskStatusStats = new EnumMap( @@ -75,6 +79,7 @@ public class DashboardModel { this.calculateTaskViolationStatusStatistics(); this.calculateMarginWithDeadLine(); this.calculateFinishedTasksEstimationAccuracyHistogram(); + this.calculateLagInTaskCompletionHistogram(); } /* Progress KPI: "Number of tasks by status" */ @@ -208,10 +213,32 @@ public class DashboardModel { deviations); } - private List createHistogram(int lowBound, int highBound, - int intervalStep, List values) { - int variableRange = highBound - lowBound; - int numberOfClasses = variableRange/intervalStep; + /* Time KPI: Lead/Lag in task completion */ + public List getLagInTaskCompletionHistogram() { + return this.lagInTaskCompletionHistogram; + } + + private void calculateLagInTaskCompletionHistogram() { + CalculateFinishedTasksLagInCompletionVisitor visitor = + new CalculateFinishedTasksLagInCompletionVisitor(); + TaskElement rootTask = getRootTask(); + rootTask.acceptVisitor(visitor); + List deviations = visitor.getDeviations(); + + Double minDeviation = Collections.min(deviations); + Double maxDeviation = Collections.max(deviations); + this.lagInTaskCompletionHistogram = createHistogram( + Collections.min(deviations), + Collections.max(deviations), + (maxDeviation - minDeviation)/LTC_NUMBER_OF_INTERVALS, + deviations); + } + + private List createHistogram(double lowBound, double highBound, + double intervalStep, List values) { + double variableRange = highBound - lowBound; + /* TODO: What if highBound == lowBound? */ + int numberOfClasses = (int)(variableRange/intervalStep); int[] classes = new int[numberOfClasses+1]; for(Double value: values) {