From 2a46cbddfd23c9f96c9b9fc58f4f040bc59fb01f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Wed, 3 Mar 2010 17:05:30 +0100 Subject: [PATCH] ItEr49S04ValidacionEProbasFuncionaisItEr48S04: Improving allocation correctness. Taking into account the availability of the resources when distributing some hours in a interval of dates. This way if at a day no hours can be assigned because it doesn't match the criteria or it's a holiday for the resource no hours are assigned. If in the interval there are no days in which could be assigned hours, no assignments are created. --- .../entities/AvailabilityCalculator.java | 4 +- .../entities/GenericResourceAllocation.java | 10 ++++- .../planner/entities/ResourceAllocation.java | 43 ++++++++++++++++--- .../entities/SpecificResourceAllocation.java | 6 +++ .../GenericResourceAllocationTest.java | 7 +++ .../SpecificResourceAllocationTest.java | 5 +++ 6 files changed, 66 insertions(+), 9 deletions(-) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/AvailabilityCalculator.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/AvailabilityCalculator.java index 7146fecd0..1ea848dd1 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/AvailabilityCalculator.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/AvailabilityCalculator.java @@ -67,8 +67,8 @@ public class AvailabilityCalculator { Collection criterions, Resource resource) { AvailabilityTimeLine result = AvailabilityTimeLine.allValid(); for (Criterion each : criterions) { - result = result.and(buildTimeline(resource.query().from(each) - .result())); + result = result.and(buildTimeline(resource + .getSatisfactionsFor(each))); } return result; } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/GenericResourceAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/GenericResourceAllocation.java index 391b399ca..c66722614 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/GenericResourceAllocation.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/GenericResourceAllocation.java @@ -32,6 +32,7 @@ import java.util.Set; import org.apache.commons.lang.Validate; import org.joda.time.LocalDate; +import org.navalplanner.business.calendars.entities.AvailabilityTimeLine; import org.navalplanner.business.calendars.entities.IWorkHours; import org.navalplanner.business.planner.entities.HoursDistributor.IResourceSelector; import org.navalplanner.business.planner.entities.HoursDistributor.ResourceWithAssignedHours; @@ -152,10 +153,11 @@ public class GenericResourceAllocation extends private class GenericAllocation extends AssignmentsAllocation { - private HoursDistributor hoursDistributor; + private final List resources; public GenericAllocation(List resources) { + this.resources = resources; hoursDistributor = new HoursDistributor(resources, getAssignedHoursForResource(), new ResourcesSatisfyingCriterionsSelector()); @@ -173,6 +175,12 @@ public class GenericResourceAllocation extends return result; } + @Override + protected AvailabilityTimeLine getResourcesAvailability() { + return AvailabilityCalculator.buildSumOfAvailabilitiesFor( + getCriterions(), resources); + } + } private IAssignedHoursForResource assignedHoursCalculatorOverriden = null; diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java index 0e9eccc9c..5aed7107a 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/ResourceAllocation.java @@ -445,22 +445,42 @@ public abstract class ResourceAllocation extends setResourcesPerDay(calculateResourcesPerDayFromAssignments()); } + protected abstract AvailabilityTimeLine getResourcesAvailability(); + private List createAssignments(LocalDate startInclusive, LocalDate endExclusive, int hours) { Validate.isTrue(hours >= 0); List assignmentsCreated = new ArrayList(); if (hours > 0) { + AvailabilityTimeLine availability = getAvailability(); + List days = getDays(startInclusive, endExclusive); - int[] hoursEachDay = hoursDistribution(days, hours); + int[] hoursEachDay = hoursDistribution(availability, days, + hours); int i = 0; for (LocalDate day : days) { - assignmentsCreated.addAll(distributeForDay(day, - hoursEachDay[i++])); + // if all days are not available, it would try to assign + // them anyway, preventing it with a check + if (availability.isValid(day)) { + assignmentsCreated.addAll(distributeForDay(day, + hoursEachDay[i])); + } + i++; } } return onlyNonZeroHours(assignmentsCreated); } + private AvailabilityTimeLine getAvailability() { + AvailabilityTimeLine resourcesAvailability = getResourcesAvailability(); + if (getTaskCalendar() != null) { + return getTaskCalendar().getAvailability().and( + resourcesAvailability); + } else { + return resourcesAvailability; + } + } + private List onlyNonZeroHours(List assignmentsCreated) { List result = new ArrayList(); for (T each : assignmentsCreated) { @@ -471,17 +491,28 @@ public abstract class ResourceAllocation extends return result; } - private int[] hoursDistribution(List days, int hoursToSum) { + private int[] hoursDistribution(AvailabilityTimeLine availability, + List days, int hoursToSum) { List shares = new ArrayList(); for (LocalDate day : days) { - shares.add(new Share(-getWorkHoursPerDay() - .getCapacityAt(day))); + shares.add(getShareAt(day, availability)); } ShareDivision original = ShareDivision.create(shares); ShareDivision newShare = original.plus(hoursToSum); return original.to(newShare); } + private Share getShareAt(LocalDate day, + AvailabilityTimeLine availability) { + if (availability.isValid(day)) { + Integer capacityAtDay = getWorkHoursPerDay() + .getCapacityAt(day); + return new Share(-capacityAtDay); + } else { + return new Share(Integer.MAX_VALUE); + } + } + protected abstract List distributeForDay(LocalDate day, int totalHours); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java index 4b3191b36..99206ece0 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/SpecificResourceAllocation.java @@ -31,6 +31,7 @@ import java.util.Set; import org.apache.commons.lang.Validate; import org.hibernate.validator.NotNull; import org.joda.time.LocalDate; +import org.navalplanner.business.calendars.entities.AvailabilityTimeLine; import org.navalplanner.business.calendars.entities.CombinedWorkHours; import org.navalplanner.business.calendars.entities.IWorkHours; import org.navalplanner.business.planner.entities.allocationalgorithms.HoursModification; @@ -142,6 +143,11 @@ public class SpecificResourceAllocation extends return Arrays.asList(SpecificDayAssignment.create(day, totalHours, resource)); } + + @Override + protected AvailabilityTimeLine getResourcesAvailability() { + return AvailabilityCalculator.getCalendarAvailabilityFor(resource); + } } @Override diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/GenericResourceAllocationTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/GenericResourceAllocationTest.java index de61fc7e9..d9bdfb05f 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/GenericResourceAllocationTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/GenericResourceAllocationTest.java @@ -46,6 +46,7 @@ import org.joda.time.Interval; import org.joda.time.LocalDate; import org.joda.time.Period; import org.junit.Test; +import org.navalplanner.business.calendars.entities.AvailabilityTimeLine; import org.navalplanner.business.calendars.entities.BaseCalendar; import org.navalplanner.business.calendars.entities.ResourceCalendar; import org.navalplanner.business.calendars.entities.SameWorkHoursEveryDay; @@ -54,6 +55,8 @@ import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourcesPerDay; import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.resources.entities.CriterionSatisfaction; +import org.navalplanner.business.resources.entities.ICriterion; import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.VirtualWorker; import org.navalplanner.business.resources.entities.Worker; @@ -151,6 +154,8 @@ public class GenericResourceAllocationTest { expect( result.getAssignedHoursDiscounting(isA(Object.class), isA(LocalDate.class))).andReturn(hours).anyTimes(); + expect(result.getSatisfactionsFor(isA(ICriterion.class))).andReturn( + new ArrayList()).anyTimes(); replay(result); return result; } @@ -210,6 +215,8 @@ public class GenericResourceAllocationTest { }).anyTimes(); expect(baseCalendar.canWork(isA(LocalDate.class))).andReturn(true) .anyTimes(); + expect(baseCalendar.getAvailability()).andReturn( + AvailabilityTimeLine.allValid()).anyTimes(); if (baseCalendar instanceof ResourceCalendar) { ResourceCalendar resourceCalendar = (ResourceCalendar) baseCalendar; expect(resourceCalendar.getCapacity()).andReturn(1); diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/SpecificResourceAllocationTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/SpecificResourceAllocationTest.java index bc3f0b2f7..b2ff707f0 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/SpecificResourceAllocationTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/SpecificResourceAllocationTest.java @@ -40,6 +40,7 @@ import org.easymock.IAnswer; import org.easymock.classextension.EasyMock; import org.joda.time.LocalDate; import org.junit.Test; +import org.navalplanner.business.calendars.entities.AvailabilityTimeLine; import org.navalplanner.business.calendars.entities.BaseCalendar; import org.navalplanner.business.calendars.entities.ResourceCalendar; import org.navalplanner.business.planner.entities.ResourcesPerDay; @@ -74,6 +75,8 @@ public class SpecificResourceAllocationTest { expect(this.calendar.toHours(isA(LocalDate.class), isA(ResourcesPerDay.class))).andAnswer( toHoursAnswer(hours)).anyTimes(); + expect(this.calendar.getAvailability()).andReturn( + AvailabilityTimeLine.allValid()).anyTimes(); replay(this.calendar); } @@ -120,6 +123,8 @@ public class SpecificResourceAllocationTest { return toHoursAnswer(hours).answer(); } }).anyTimes(); + expect(this.calendar.getAvailability()).andReturn( + AvailabilityTimeLine.allValid()).anyTimes(); replay(this.calendar); }