From a219fa75a1aa3100e640144c4efeee214b32d3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=93scar=20Gonz=C3=A1lez=20Fern=C3=A1ndez?= Date: Mon, 24 Jan 2011 22:53:49 +0100 Subject: [PATCH] Not allow to allocate on intervals beyond a task's bounds Inside the task's bounds the allocations can grow until reaching task's bounds but they can't shrink, i.e. the allocating zero hours the last day would keep the same end date. FEA: ItEr69S08AdvanceAllocationFix --- .../planner/entities/ResourceAllocation.java | 78 +++++++++++++------ .../entities/SpecificResourceAllocation.java | 8 +- .../test/planner/daos/TaskElementDAOTest.java | 7 +- .../SpecificResourceAllocationTest.java | 68 ++++++++++++++++ .../UntilFillingHoursAllocatorTest.java | 1 + 5 files changed, 135 insertions(+), 27 deletions(-) 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 771d95cf8..aaf64fecd 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 @@ -718,16 +718,11 @@ public abstract class ResourceAllocation extends private void allocate(LocalDate startInclusive, LocalDate endExclusive, EffortDuration durationToAssign) { - IntraDayDate firstDayNotConsolidated = getTask() - .getFirstDayNotConsolidated(); - IntraDayDate start = IntraDayDate.max( - IntraDayDate.startOfDay(startInclusive), - firstDayNotConsolidated); - List assignmentsCreated = createAssignments( - IntraDayDate.startOfDay(startInclusive), - IntraDayDate.startOfDay(endExclusive), durationToAssign); - resetAssigmentsForInterval(start.getDate(), endExclusive, - assignmentsCreated); + IntervalInsideTask interval = new IntervalInsideTask( + startInclusive, endExclusive); + List assignmentsCreated = createAssignments(interval.getStart(), + interval.getEnd(), durationToAssign); + resetAssigmentsForInterval(interval, assignmentsCreated); } protected abstract AvailabilityTimeLine getResourcesAvailability(); @@ -855,20 +850,59 @@ public abstract class ResourceAllocation extends getDayAssignmentsState().setIntraDayEnd(intraDayEnd); } - protected void resetAssigmentsForInterval(LocalDate startInclusive, - LocalDate endExclusive, List assignmentsCreated) { - LocalDate realEndExclusive = getEndDateGiven(assignmentsCreated); - boolean endMovedAfterCurrentEnd = realEndExclusive != null - && getEndDate() != null - && getEndDate().compareTo(realEndExclusive) < 0; - removingAssignments(withoutConsolidated(getAssignments(startInclusive, - endExclusive))); + class IntervalInsideTask { + + private final IntraDayDate start; + + private final IntraDayDate end; + + public IntervalInsideTask(LocalDate startInclusive, + LocalDate endExclusive) { + this.start = IntraDayDate.max(IntraDayDate + .startOfDay(startInclusive), getTask() + .getFirstDayNotConsolidated()); + this.end = IntraDayDate.min(task.getIntraDayEndDate(), + IntraDayDate.startOfDay(endExclusive)); + } + + public IntraDayDate getStart() { + return this.start; + } + + public IntraDayDate getEnd() { + return this.end; + } + + public List getAssignmentsOnInterval() { + return getAssignments(this.start.getDate(), + this.end.asExclusiveEnd()); + } + + } + + protected void resetAssigmentsForInterval(IntervalInsideTask interval, + List assignmentsCreated) { + IntraDayDate originalStart = getIntraDayStartDate(); + IntraDayDate originalEnd = getIntraDayEndDate(); + + removingAssignments(withoutConsolidated(interval + .getAssignmentsOnInterval())); addingAssignments(assignmentsCreated); updateOriginalTotalAssigment(); - if (endMovedAfterCurrentEnd) { - getDayAssignmentsState().setIntraDayEnd(null); - } updateResourcesPerDay(); + + // The resource allocation cannot grow beyond the start of the task. + // This + // is guaranteed by IntervalInsideTask. It also cannot shrink from the + // original size, this is guaranteed by originalStart + getDayAssignmentsState().setIntraDayStart( + IntraDayDate.min(originalStart, interval.getStart())); + + // The resource allocation cannot grow beyond the end of the task. This + // is guaranteed by IntervalInsideTask. It also cannot shrink from the + // original size, this is guaranteed by originalEnd + getDayAssignmentsState().setIntraDayEnd( + IntraDayDate.max(originalEnd, interval.getEnd())); } private static List withoutConsolidated( @@ -1498,7 +1532,7 @@ public abstract class ResourceAllocation extends LocalDate l = getEndDateGiven(getAssignments()); if (l == null) { - return null; + return task.getIntraDayEndDate(); } return IntraDayDate.startOfDay(l); } 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 279ff090f..d6c29ea06 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 @@ -305,12 +305,14 @@ public class SpecificResourceAllocation extends public void allocateKeepingProportions(LocalDate start, LocalDate endExclusive, int newHoursForInterval) { - List assignments = getAssignments(start, endExclusive); + IntervalInsideTask interval = new IntervalInsideTask(start, + endExclusive); + List assignments = interval.getAssignmentsOnInterval(); ProportionalDistributor distributor = ProportionalDistributor .create(asHours(assignments)); int[] newHoursPerDay = distributor.distribute(newHoursForInterval); - resetAssigmentsForInterval(start, endExclusive, assignmentsForNewHours( - assignments, newHoursPerDay)); + resetAssigmentsForInterval(interval, + assignmentsForNewHours(assignments, newHoursPerDay)); } private List assignmentsForNewHours( diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/daos/TaskElementDAOTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/daos/TaskElementDAOTest.java index 48e8b1ca1..e7108f53c 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/daos/TaskElementDAOTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/daos/TaskElementDAOTest.java @@ -66,19 +66,20 @@ import org.navalplanner.business.planner.daos.ITaskElementDAO; import org.navalplanner.business.planner.daos.ITaskSourceDAO; import org.navalplanner.business.planner.daos.TaskElementDAO; import org.navalplanner.business.planner.entities.Dependency; +import org.navalplanner.business.planner.entities.Dependency.Type; import org.navalplanner.business.planner.entities.SpecificResourceAllocation; import org.navalplanner.business.planner.entities.SubcontractedTaskData; import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.planner.entities.TaskElement; import org.navalplanner.business.planner.entities.TaskGroup; import org.navalplanner.business.planner.entities.TaskMilestone; -import org.navalplanner.business.planner.entities.Dependency.Type; import org.navalplanner.business.resources.daos.IResourceDAO; import org.navalplanner.business.resources.entities.Worker; import org.navalplanner.business.scenarios.IScenarioManager; import org.navalplanner.business.scenarios.bootstrap.IScenariosBootstrap; import org.navalplanner.business.scenarios.entities.OrderVersion; import org.navalplanner.business.test.externalcompanies.daos.ExternalCompanyDAOTest; +import org.navalplanner.business.workingday.IntraDayDate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.annotation.NotTransactional; import org.springframework.test.context.ContextConfiguration; @@ -551,7 +552,9 @@ public class TaskElementDAOTest { SpecificResourceAllocation allocation = SpecificResourceAllocation.create(task); allocation.setResource(createValidWorker()); - LocalDate start = new LocalDate(2000, 2, 4); + LocalDate start = task.getStartAsLocalDate(); + task.setIntraDayEndDate(IntraDayDate.startOfDay(start + .plusDays(2))); allocation.onInterval(start, start.plusDays(2)).allocateHours(16); assertTrue(allocation.getAssignedHours() > 0); 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 bf4b4dc96..59297ac09 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 @@ -317,6 +317,74 @@ public class SpecificResourceAllocationTest { assertThat(specificResourceAllocation.getAssignments(), haveHours(5, 5)); } + @Test + public void thePartOfTheIntervalUsedIsTheOneOverlapping() { + LocalDate start = new LocalDate(2000, 2, 4); + givenSpecificResourceAllocation(start, 4); + specificResourceAllocation.onInterval(start.plusDays(1), + start.plusDays(6)).allocateHours(12); + assertThat(specificResourceAllocation.getAssignments(), + haveHours(4, 4, 4)); + } + + @Test + public void thePartOfTheIntervalUsedIsTheOneOverlappingWithTheTask() { + LocalDate start = new LocalDate(2000, 2, 4); + givenSpecificResourceAllocation(start, 4); + + specificResourceAllocation.fromStartUntil(start.plusDays(2)) + .allocateHours(16); + specificResourceAllocation.onInterval(start, start.plusDays(6)) + .allocateHours(12); + + assertThat(specificResourceAllocation.getAssignments(), + haveHours(3, 3, 3, 3)); + } + + @Test + public void theEndIsNotChangedIfAZeroAllocationIsDoneInTheLastDay() { + LocalDate start = new LocalDate(2000, 2, 4); + givenSpecificResourceAllocation(start, 4); + LocalDate end = start.plusDays(4); + + specificResourceAllocation.fromStartUntil(end).allocateHours(32); + specificResourceAllocation.onInterval(start.plusDays(3), end) + .allocateHours(0); + + assertThat(specificResourceAllocation.getIntraDayEndDate(), + equalTo(IntraDayDate.startOfDay(end))); + } + + @Test + public void theEndCanGrowUntilReachingTheEndOfTheTask() { + LocalDate start = new LocalDate(2000, 2, 4); + givenSpecificResourceAllocation(start, 4); + LocalDate end = start.plusDays(4); + + specificResourceAllocation.fromStartUntil(end.minusDays(1)) + .allocateHours(24); + assertThat(specificResourceAllocation.getIntraDayEndDate(), + equalTo(IntraDayDate.startOfDay(end.minusDays(1)))); + + specificResourceAllocation.onInterval(start, end).allocateHours(32); + assertThat(specificResourceAllocation.getAssignments(), + haveHours(8, 8, 8, 8)); + assertThat(specificResourceAllocation.getIntraDayEndDate(), + equalTo(IntraDayDate.startOfDay(end))); + } + + @Test + public void theStartIsNotChangedIfAZeroAllocationIsDoneInTheFirstDay() { + LocalDate start = new LocalDate(2000, 2, 4); + givenSpecificResourceAllocation(start, 4); + specificResourceAllocation.fromStartUntil(start.plusDays(4)) + .allocateHours(32); + specificResourceAllocation.onInterval(start, start.plusDays(1)) + .allocateHours(0); + assertThat(specificResourceAllocation.getIntraDayStartDate(), + equalTo(IntraDayDate.startOfDay(start))); + } + @Test public void canAssignFromStartUntilEnd() { LocalDate start = new LocalDate(2000, 2, 4); diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/UntilFillingHoursAllocatorTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/UntilFillingHoursAllocatorTest.java index dda83c8aa..51608d038 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/UntilFillingHoursAllocatorTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/planner/entities/UntilFillingHoursAllocatorTest.java @@ -280,6 +280,7 @@ public class UntilFillingHoursAllocatorTest { @Test public void theResourcesPerDayAreKeptCorrectlyCalculatedAfterUpdatingTheEndInterval() { + givenTaskOfDaysLength(10); final ResourcesPerDay oneResourcePerDay = ResourcesPerDay.amount(1); givenSpecificAllocations(oneResourcePerDay); ResourceAllocation.allocating(allocations).untilAllocating(30);