diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/IAllocateHoursOnInterval.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/IAllocateHoursOnInterval.java
index 050bb17fc..fb2c513c0 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/IAllocateHoursOnInterval.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/IAllocateHoursOnInterval.java
@@ -20,6 +20,31 @@
*/
package org.navalplanner.business.planner.entities;
+import java.util.List;
+
+import org.navalplanner.business.workingday.EffortDuration;
+
public interface IAllocateHoursOnInterval {
+
void allocateHours(int hours);
+
+ /**
+ *
+ * It tries to allocate the specified durations on the originally specified
+ * interval. It tries to fit them to the interval. If the specified list has
+ * less days than the days required by the interval, the end of the list is
+ * padded with zeroes. If the specified list has more days than the days
+ * required the trailing days are discarded.
+ *
+ *
+ * If the allocation is done within the bounds of the task, the durations
+ * specified outside the task's bounds are discarded.
+ *
+ *
+ * If for some day no allocation can't be done, i.e. the day is considered
+ * unavailable, the real assignment will be zero.
+ *
+ * @param durationsByDay
+ */
+ void allocate(List durationsByDay);
}
\ No newline at end of file
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 c569f2759..a0ddfb1af 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
@@ -720,13 +720,13 @@ public abstract class ResourceAllocation extends
endDate);
}
- private List getDays(IntraDayDate startInclusive,
+ private Iterable getDays(IntraDayDate startInclusive,
IntraDayDate endExclusive) {
- Validate.notNull(startInclusive);
- Validate.notNull(endExclusive);
Validate.isTrue(startInclusive.compareTo(endExclusive) <= 0,
"the end must be equal or posterior than start");
- return IntraDayDate.toList(startInclusive.daysUntil(endExclusive));
+ Iterable daysUntil = startInclusive
+ .daysUntil(endExclusive);
+ return daysUntil;
}
private final class AllocateResourcesPerDayOnInterval implements
@@ -817,6 +817,21 @@ public abstract class ResourceAllocation extends
allocationInterval, duration);
allocationInterval.resetAssignments(assignmentsCreated);
}
+
+ @Override
+ public void allocate(List durationsByDay) {
+ allocateDurationsByDay(allocationInterval, durationsByDay);
+ }
+ }
+
+ private void allocateDurationsByDay(AllocationInterval interval,
+ List durationsByDay) {
+ List rightSlice = interval
+ .getRightSlice(durationsByDay);
+ AvailabilityTimeLine availability = getAvailability();
+ List assignments = createAssignments(interval, availability,
+ rightSlice.toArray(new EffortDuration[0]));
+ interval.resetAssignments(assignments);
}
@Override
@@ -829,6 +844,15 @@ public abstract class ResourceAllocation extends
public void allocateHours(int hours) {
allocateTheWholeAllocation(interval, hours(hours));
}
+
+ @Override
+ public void allocate(List durationsByDay) {
+ List rightSlice = interval
+ .getRightSlice(durationsByDay);
+ AvailabilityTimeLine availability = getAvailability();
+ createAssignments(interval, availability,
+ rightSlice.toArray(new EffortDuration[0]));
+ }
};
}
@@ -842,6 +866,11 @@ public abstract class ResourceAllocation extends
public void allocateHours(int hours) {
allocateTheWholeAllocation(interval, hours(hours));
}
+
+ @Override
+ public void allocate(List durationsByDay) {
+ allocateDurationsByDay(interval, durationsByDay);
+ }
};
}
@@ -863,24 +892,31 @@ public abstract class ResourceAllocation extends
private List createAssignments(AllocationInterval interval,
EffortDuration durationToAssign) {
- List assignmentsCreated = new ArrayList();
AvailabilityTimeLine availability = getAvailability();
- List days = getDays(interval.getStartInclusive(),
+ Iterable days = getDays(interval.getStartInclusive(),
interval.getEndExclusive());
EffortDuration[] durationsEachDay = secondsDistribution(
availability, days, durationToAssign);
+ return createAssignments(interval, availability, durationsEachDay);
+ }
+
+ private List createAssignments(AllocationInterval interval,
+ AvailabilityTimeLine availability,
+ EffortDuration[] durationsEachDay) {
+ List result = new ArrayList();
int i = 0;
- for (PartialDay day : days) {
+ for (PartialDay day : getDays(interval.getStartInclusive(),
+ interval.getEndExclusive())) {
// if all days are not available, it would try to assign
// them anyway, preventing it with a check
if (availability.isValid(day.getDate())) {
- assignmentsCreated.addAll(distributeForDay(day.getDate(),
+ result.addAll(distributeForDay(day.getDate(),
durationsEachDay[i]));
}
i++;
}
- return onlyNonZeroHours(assignmentsCreated);
+ return onlyNonZeroHours(result);
}
private AvailabilityTimeLine getAvailability() {
@@ -905,7 +941,7 @@ public abstract class ResourceAllocation extends
}
private EffortDuration[] secondsDistribution(
- AvailabilityTimeLine availability, List days,
+ AvailabilityTimeLine availability, Iterable days,
EffortDuration duration) {
List shares = new ArrayList();
for (PartialDay each : days) {
@@ -985,11 +1021,18 @@ public abstract class ResourceAllocation extends
class AllocationInterval {
+ private IntraDayDate originalStart;
+
+ private IntraDayDate originalEnd;
+
private final IntraDayDate start;
private final IntraDayDate end;
- private AllocationInterval(IntraDayDate start, IntraDayDate end) {
+ AllocationInterval(IntraDayDate originalStart,
+ IntraDayDate originalEnd, IntraDayDate start, IntraDayDate end) {
+ this.originalStart = originalStart;
+ this.originalEnd = originalEnd;
IntraDayDate startConsideringConsolidated = task
.hasConsolidations() ? IntraDayDate
.max(task.getFirstDayNotConsolidated(), start) : start;
@@ -998,17 +1041,33 @@ public abstract class ResourceAllocation extends
this.end = IntraDayDate.max(this.start, end);
}
+ AllocationInterval(IntraDayDate start, IntraDayDate end) {
+ this(start, end, start, end);
+ }
+
+ AllocationInterval(LocalDate startInclusive, LocalDate endExclusive) {
+ this(IntraDayDate.startOfDay(startInclusive), IntraDayDate
+ .startOfDay(endExclusive));
+ }
+
+ public List getRightSlice(List original) {
+ List result = new ArrayList(
+ original);
+ final int numberOfDaysToFill = originalStart
+ .numberOfDaysUntil(originalEnd);
+ for (int i = 0; i < numberOfDaysToFill - original.size(); i++) {
+ result.add(zero());
+ }
+ return result.subList(originalStart.numberOfDaysUntil(start),
+ result.size() - end.numberOfDaysUntil(originalEnd));
+ }
+
+
public void resetAssignments(List assignmentsCreated) {
resetAssigmentsFittingAllocationDatesToResultingAssignments(this,
assignmentsCreated);
}
- public AllocationInterval(LocalDate startInclusive,
- LocalDate endExclusive) {
- this(IntraDayDate.startOfDay(startInclusive), IntraDayDate
- .startOfDay(endExclusive));
- }
-
public IntraDayDate getStartInclusive() {
return this.start;
}
@@ -1034,7 +1093,8 @@ public abstract class ResourceAllocation extends
AllocationIntervalInsideTask(IntraDayDate startInclusive,
IntraDayDate endExclusive) {
- super(IntraDayDate.max(startInclusive, getTask()
+ super(startInclusive, endExclusive, IntraDayDate.max(
+ startInclusive, getTask()
.getFirstDayNotConsolidated()), IntraDayDate.min(
endExclusive, task.getIntraDayEndDate()));
}
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 3b1a80b94..5169c0449 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
@@ -840,9 +840,9 @@ public class GenericResourceAllocationTest {
final int hoursOnSubinterval = 3;
int daysSubinterval = 2;
- genericResourceAllocation.forResources(workers).onIntervalWithinTask(start,
- start.plusDays(daysSubinterval)).allocateHours(
- hoursOnSubinterval);
+ genericResourceAllocation.forResources(workers)
+ .onIntervalWithinTask(start, start.plusDays(daysSubinterval))
+ .allocateHours(hoursOnSubinterval);
assertThat(genericResourceAllocation.getAssignedHours(),
equalTo(hoursOnSubinterval + (days - daysSubinterval)
* workableHoursDay));
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 0d4262efc..69be03884 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
@@ -39,6 +39,7 @@ import static org.navalplanner.business.test.planner.entities.DayAssignmentMatch
import static org.navalplanner.business.test.planner.entities.DayAssignmentMatchers.haveResourceAllocation;
import static org.navalplanner.business.workingday.EffortDuration.hours;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -316,6 +317,73 @@ public class SpecificResourceAllocationTest {
assertThat(specificResourceAllocation.getAssignments(), haveHours(5, 5));
}
+ @Test
+ public void theHoursForEachDayCanBeAssigned() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start,
+ start.plusDays(4)).allocate(
+ Arrays.asList(hours(4), hours(8), hours(4), hours(8)));
+ assertThat(specificResourceAllocation.getAssignments(),
+ haveHours(4, 8, 4, 8));
+ }
+
+ @Test
+ public void ifLessDaysAreSpecifiedTheInitialDaysAreAllocated() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start,
+ start.plusDays(4)).allocate(
+ Arrays.asList(hours(4), hours(8), hours(4)));
+ assertThat(specificResourceAllocation.getAssignments(),
+ haveHours(4, 8, 4));
+ }
+
+ @Test
+ public void ifMoreDaysAreSpecifiedTheInitialDaysAreAllocated() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start,
+ start.plusDays(4))
+ .allocate(
+ Arrays.asList(hours(4), hours(8), hours(4), hours(4),
+ hours(3)));
+ assertThat(specificResourceAllocation.getAssignments(),
+ haveHours(4, 8, 4, 4));
+ }
+
+ @Test
+ public void theDaysSpecifiedOutsideBoundsAreDiscarded() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start.minusDays(2),
+ start.plusDays(1)).allocate(
+ Arrays.asList(hours(2), hours(3), hours(4)));
+ assertThat(specificResourceAllocation.getAssignments(), haveHours(4));
+ }
+
+ @Test
+ public void combineOutsideBoundsAndZeroPadding() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start.minusDays(2),
+ start.plusDays(1)).allocate(Arrays.asList(hours(2), hours(3)));
+ assertThat(specificResourceAllocation.getAssignments(), haveHours());
+ }
+
+ @Test
+ public void theDaysSpecifiedOutsideTheTaskAreDiscarded() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onIntervalWithinTask(start.minusDays(1),
+ start.plusDays(4)).allocate(
+ Arrays.asList(hours(10), hours(4), hours(8), hours(4),
+ hours(4), hours(3)));
+ List assigments = specificResourceAllocation
+ .getAssignments();
+ assertThat(assigments, haveHours(4, 8, 4, 4));
+ }
+
@Test
public void theIntervalWithinTaskCanBeMadeOfIntraDayDates() {
LocalDate start = new LocalDate(2000, 2, 4);
@@ -447,6 +515,19 @@ public class SpecificResourceAllocationTest {
haveHours(8, 8, 8, 8, 4));
}
+ @Test
+ public void canAllocateOutsideTheBoundsSpecifyingTheHoursForEachDay() {
+ LocalDate start = new LocalDate(2000, 2, 4);
+ givenSpecificResourceAllocation(start, 4);
+ specificResourceAllocation.onInterval(
+ IntraDayDate.startOfDay(start.minusDays(1)),
+ IntraDayDate.create(start.plusDays(4), hours(4))).allocate(
+ Arrays.asList(hours(8), hours(2), hours(8), hours(8), hours(8),
+ hours(4)));
+ assertThat(specificResourceAllocation.getAssignments(),
+ haveHours(8, 2, 8, 8, 8, 4));
+ }
+
@Test
public void allocatingZeroHoursAtTheEndShrinksTheAllocation() {
LocalDate start = new LocalDate(2000, 2, 4);