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);