diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/entities/IOrderResourceLoadCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/IOrderResourceLoadCalculator.java new file mode 100644 index 000000000..e76d2704b --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/IOrderResourceLoadCalculator.java @@ -0,0 +1,49 @@ +/* + * 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 org.libreplan.business.orders.entities.Order; +import org.libreplan.business.planner.chart.ContiguousDaysLine; +import org.libreplan.business.resources.entities.IAssignmentsOnResourceCalculator; +import org.libreplan.business.workingday.EffortDuration; + + +/** + * @author Óscar González Fernández + * @author Diego Pino García + * + * Utility class for calculating 'Resource Load' values from an Order + */ +public interface IOrderResourceLoadCalculator { + + void setOrder(Order order, + IAssignmentsOnResourceCalculator assignmentsOnResourceCalculator); + + ContiguousDaysLine getMaxCapacityOnResources(); + + ContiguousDaysLine getOrderLoad(); + + ContiguousDaysLine getAllLoad(); + + ContiguousDaysLine getOrderOverload(); + + ContiguousDaysLine getAllOverload(); + +} diff --git a/libreplan-business/src/main/java/org/libreplan/business/planner/entities/OrderResourceLoadCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/OrderResourceLoadCalculator.java new file mode 100644 index 000000000..ea86e09af --- /dev/null +++ b/libreplan-business/src/main/java/org/libreplan/business/planner/entities/OrderResourceLoadCalculator.java @@ -0,0 +1,218 @@ +/* + * 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.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.joda.time.LocalDate; +import org.libreplan.business.calendars.entities.AvailabilityTimeLine; +import org.libreplan.business.orders.entities.Order; +import org.libreplan.business.planner.chart.ContiguousDaysLine; +import org.libreplan.business.planner.chart.ContiguousDaysLine.OnDay; +import org.libreplan.business.planner.chart.ResourceLoadChartData; +import org.libreplan.business.planner.entities.DayAssignment.FilterType; +import org.libreplan.business.resources.entities.IAssignmentsOnResourceCalculator; +import org.libreplan.business.resources.entities.Resource; +import org.libreplan.business.workingday.EffortDuration; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +/** + * @author Óscar González Fernández + * @author Diego Pino García + */ +@Component +@Scope(BeanDefinition.SCOPE_SINGLETON) +public class OrderResourceLoadCalculator implements IOrderResourceLoadCalculator { + + private Order order; + + private IAssignmentsOnResourceCalculator assignmentsOnResourceCalculator; + + private ContiguousDaysLine> orderAssignments; + + private ContiguousDaysLine> filteredAssignments; + + private ContiguousDaysLine maxCapacityOnResources; + + private ContiguousDaysLine orderLoad; + + private ContiguousDaysLine allLoad; + + private ContiguousDaysLine orderOverload; + + private ContiguousDaysLine allOverload; + + @Override + public void setOrder(Order order, + IAssignmentsOnResourceCalculator assignmentsOnResourceCalculator) { + this.order = order; + this.assignmentsOnResourceCalculator = assignmentsOnResourceCalculator; + initializeValues(); + } + + private void initializeValues() { + orderAssignments = null; + filteredAssignments = null; + maxCapacityOnResources = null; + orderLoad = null; + allLoad = null; + orderOverload = null; + allOverload = null; + } + + @Override + public ContiguousDaysLine getMaxCapacityOnResources() { + if (maxCapacityOnResources == null) { + maxCapacityOnResources = getOrderAssignments() + .transform(ResourceLoadChartData + .extractAvailabilityOnAssignedResources()); + } + return maxCapacityOnResources; + } + + private ContiguousDaysLine> getOrderAssignments() { + if (orderAssignments == null) { + List orderDayAssignments = order + .getDayAssignments(FilterType.WITHOUT_DERIVED); + orderAssignments = ContiguousDaysLine.byDay(orderDayAssignments); + } + return orderAssignments; + } + + @Override + public ContiguousDaysLine getOrderLoad() { + if (orderLoad == null) { + orderLoad = getOrderAssignments() + .transform(ResourceLoadChartData.extractLoad()); + } + return orderLoad; + } + + @Override + public ContiguousDaysLine getAllLoad() { + if (allLoad == null) { + allLoad = getFilteredAssignments() + .transform(ResourceLoadChartData.extractLoad()); + } + return allLoad; + } + + private ContiguousDaysLine> getFilteredAssignments() { + if (filteredAssignments == null) { + ContiguousDaysLine> allAssignments = allAssignments(getOrderAssignments()); + filteredAssignments = filterAllAssignmentsByOrderResources( + allAssignments, getOrderAssignments()); + } + return filteredAssignments; + } + + private ContiguousDaysLine> filterAllAssignmentsByOrderResources( + ContiguousDaysLine> allAssignments, + ContiguousDaysLine> orderAssignments) { + List filteredAssignments = new ArrayList(); + + Iterator>> iterator = orderAssignments + .iterator(); + while (iterator.hasNext()) { + OnDay> onDay = iterator.next(); + Set resources = getResources(onDay.getValue()); + filteredAssignments.addAll(filterAssignmentsByResource( + allAssignments.get(onDay.getDay()), resources)); + } + return ContiguousDaysLine.byDay(filteredAssignments); + } + + private List filterAssignmentsByResource( + List list, Set resources) { + List result = new ArrayList(); + for (DayAssignment each : list) { + if (resources.contains(each.getResource())) { + result.add(each); + } + } + return result; + } + + private Set getResources(List dayAssignments) { + Set resources = new HashSet(); + for (DayAssignment each : dayAssignments) { + resources.add(each.getResource()); + } + return resources; + } + + private ContiguousDaysLine> allAssignments( + ContiguousDaysLine> orderAssignments) { + if (orderAssignments.isNotValid()) { + return ContiguousDaysLine.> invalid(); + } + return allAssignmentsOnResourcesAt(orderAssignments.getStart(), + orderAssignments.getEndExclusive()); + } + + private ContiguousDaysLine> allAssignmentsOnResourcesAt( + LocalDate startInclusive, LocalDate endExclusive) { + AvailabilityTimeLine.Interval interval = AvailabilityTimeLine.Interval + .create(startInclusive, endExclusive); + List resourcesDayAssignments = new ArrayList(); + for (Resource resource : order.getResources(FilterType.WITHOUT_DERIVED)) { + resourcesDayAssignments.addAll(insideInterval(interval, + assignmentsOnResourceCalculator.getAssignments(resource))); + } + return ContiguousDaysLine.byDay(resourcesDayAssignments); + } + + private List insideInterval( + AvailabilityTimeLine.Interval interval, + List assignments) { + List result = new ArrayList(); + for (DayAssignment each : assignments) { + if (interval.includes(each.getDay())) { + result.add(each); + } + } + return result; + } + + @Override + public ContiguousDaysLine getOrderOverload() { + if (orderOverload == null) { + orderOverload = getOrderAssignments() + .transform(ResourceLoadChartData.extractOverload()); + } + return orderOverload; + } + + @Override + public ContiguousDaysLine getAllOverload() { + if (allOverload == null) { + allOverload = getFilteredAssignments() + .transform(ResourceLoadChartData.extractOverload()); + } + return allOverload; + } + +} 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 9c04f7c78..3bcfaaf95 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 @@ -34,7 +34,6 @@ import java.util.Date; import java.util.EnumSet; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -44,7 +43,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.DateTime; import org.joda.time.LocalDate; -import org.libreplan.business.calendars.entities.AvailabilityTimeLine; import org.libreplan.business.common.AdHocTransactionService; import org.libreplan.business.common.IAdHocTransactionService; import org.libreplan.business.common.IOnTransaction; @@ -56,12 +54,9 @@ import org.libreplan.business.orders.entities.Order; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.orders.entities.OrderStatusEnum; import org.libreplan.business.planner.chart.ContiguousDaysLine; -import org.libreplan.business.planner.chart.ContiguousDaysLine.OnDay; -import org.libreplan.business.planner.chart.ResourceLoadChartData; -import org.libreplan.business.planner.entities.DayAssignment; -import org.libreplan.business.planner.entities.DayAssignment.FilterType; import org.libreplan.business.planner.entities.ICostCalculator; import org.libreplan.business.planner.entities.IOrderEarnedValueCalculator; +import org.libreplan.business.planner.entities.IOrderResourceLoadCalculator; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.TaskGroup; import org.libreplan.business.resources.entities.CriterionSatisfaction; @@ -262,6 +257,9 @@ public class OrderPlanningModel implements IOrderPlanningModel { @Autowired private IOrderEarnedValueCalculator earnedValueCalculator; + @Autowired + private IOrderResourceLoadCalculator resourceLoadCalculator; + private List earnedValueChartConfigurationCheckboxes = new ArrayList(); private List keepAliveChartVisibilityListeners = new ArrayList(); @@ -1193,10 +1191,20 @@ public class OrderPlanningModel implements IOrderPlanningModel { }); } - public static final String COLOR_ASSIGNED_LOAD_GLOBAL = "#E0F3D3"; // Soft - // green - public static final String COLOR_OVERLOAD_GLOBAL = "#FFD4C2"; // Soft red + // Soft green + public static final String COLOR_ASSIGNED_LOAD_GLOBAL = "#E0F3D3"; + // Soft red + public static final String COLOR_OVERLOAD_GLOBAL = "#FFD4C2"; + + /** + * + * @author Óscar González Fernández + * @author Diego Pino García + * + * Calculates 'Resource Load' values and set them in the Order + * 'Resource Load' chart + */ private class OrderLoadChartFiller extends LoadChartFiller { private final Order order; @@ -1212,25 +1220,18 @@ public class OrderPlanningModel implements IOrderPlanningModel { @Override protected Plotinfo[] getPlotInfos(Interval interval) { - List orderDayAssignments = order - .getDayAssignments(FilterType.WITHOUT_DERIVED); - ContiguousDaysLine> orderAssignments = ContiguousDaysLine - .byDay(orderDayAssignments); - ContiguousDaysLine> allAssignments = allAssignments(orderAssignments); - ContiguousDaysLine> filteredAssignments = filterAllAssignmentsByOrderResources( - allAssignments, orderAssignments); + resourceLoadCalculator.setOrder(order, planningState.getAssignmentsCalculator()); - ContiguousDaysLine maxCapacityOnResources = orderAssignments - .transform(ResourceLoadChartData - .extractAvailabilityOnAssignedResources()); - ContiguousDaysLine orderLoad = orderAssignments - .transform(ResourceLoadChartData.extractLoad()); - ContiguousDaysLine allLoad = filteredAssignments - .transform(ResourceLoadChartData.extractLoad()); - ContiguousDaysLine orderOverload = orderAssignments - .transform(ResourceLoadChartData.extractOverload()); - ContiguousDaysLine allOverload = filteredAssignments - .transform(ResourceLoadChartData.extractOverload()); + ContiguousDaysLine maxCapacityOnResources = resourceLoadCalculator + .getMaxCapacityOnResources(); + ContiguousDaysLine orderLoad = resourceLoadCalculator + .getOrderLoad(); + ContiguousDaysLine allLoad = resourceLoadCalculator + .getAllLoad(); + ContiguousDaysLine orderOverload = resourceLoadCalculator + .getOrderOverload(); + ContiguousDaysLine allOverload = resourceLoadCalculator + .getAllOverload(); Plotinfo plotOrderLoad = createPlotinfoFromDurations( groupAsNeededByZoom(toSortedMap(ContiguousDaysLine.min( @@ -1272,76 +1273,6 @@ public class OrderPlanningModel implements IOrderPlanningModel { plotMaxCapacity, plotOtherLoad, plotOrderLoad }; } - private ContiguousDaysLine> filterAllAssignmentsByOrderResources( - ContiguousDaysLine> allAssignments, - ContiguousDaysLine> orderAssignments) { - List filteredAssignments = new ArrayList(); - - Iterator>> iterator = orderAssignments - .iterator(); - while (iterator.hasNext()) { - OnDay> onDay = iterator.next(); - Set resources = getResources(onDay.getValue()); - filteredAssignments.addAll(filterAssignmentsByResource( - allAssignments.get(onDay.getDay()), resources)); - } - return ContiguousDaysLine.byDay(filteredAssignments); - } - - private List filterAssignmentsByResource( - List list, Set resources) { - List result = new ArrayList(); - for (DayAssignment each : list) { - if (resources.contains(each.getResource())) { - result.add(each); - } - } - return result; - } - - private Set getResources(List dayAssignments) { - Set resources = new HashSet(); - for (DayAssignment each : dayAssignments) { - resources.add(each.getResource()); - } - return resources; - } - - private ContiguousDaysLine> allAssignments( - ContiguousDaysLine> orderAssignments) { - if (orderAssignments.isNotValid()) { - return ContiguousDaysLine.> invalid(); - } - return allAssignmentsOnResourcesAt(orderAssignments.getStart(), - orderAssignments.getEndExclusive()); - } - - private ContiguousDaysLine> allAssignmentsOnResourcesAt( - LocalDate startInclusive, LocalDate endExclusive) { - AvailabilityTimeLine.Interval interval = AvailabilityTimeLine.Interval - .create(startInclusive, endExclusive); - List resourcesDayAssignments = new ArrayList(); - for (Resource resource : order - .getResources(FilterType.WITHOUT_DERIVED)) { - resourcesDayAssignments.addAll(insideInterval(interval, - planningState.getAssignmentsCalculator() - .getAssignments(resource))); - } - return ContiguousDaysLine.byDay(resourcesDayAssignments); - } - - private List insideInterval( - AvailabilityTimeLine.Interval interval, - List assignments) { - List result = new ArrayList(); - for (DayAssignment each : assignments) { - if (interval.includes(each.getDay())) { - result.add(each); - } - } - return result; - } - } /**