Add method for specifying several days together in an interval

FEA: ItEr74S04BugFixing
This commit is contained in:
Óscar González Fernández 2011-04-14 02:42:12 +02:00
parent 8520456ad8
commit 4063b6d293
4 changed files with 187 additions and 21 deletions

View file

@ -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);
/**
* <p>
* 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.
* </p>
* <p>
* If the allocation is done within the bounds of the task, the durations
* specified outside the task's bounds are discarded.
* </p>
* <p>
* If for some day no allocation can't be done, i.e. the day is considered
* unavailable, the real assignment will be zero.
* </p>
* @param durationsByDay
*/
void allocate(List<EffortDuration> durationsByDay);
}

View file

@ -720,13 +720,13 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
endDate);
}
private List<PartialDay> getDays(IntraDayDate startInclusive,
private Iterable<PartialDay> 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<PartialDay> daysUntil = startInclusive
.daysUntil(endExclusive);
return daysUntil;
}
private final class AllocateResourcesPerDayOnInterval implements
@ -817,6 +817,21 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
allocationInterval, duration);
allocationInterval.resetAssignments(assignmentsCreated);
}
@Override
public void allocate(List<EffortDuration> durationsByDay) {
allocateDurationsByDay(allocationInterval, durationsByDay);
}
}
private void allocateDurationsByDay(AllocationInterval interval,
List<EffortDuration> durationsByDay) {
List<EffortDuration> rightSlice = interval
.getRightSlice(durationsByDay);
AvailabilityTimeLine availability = getAvailability();
List<T> assignments = createAssignments(interval, availability,
rightSlice.toArray(new EffortDuration[0]));
interval.resetAssignments(assignments);
}
@Override
@ -829,6 +844,15 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
public void allocateHours(int hours) {
allocateTheWholeAllocation(interval, hours(hours));
}
@Override
public void allocate(List<EffortDuration> durationsByDay) {
List<EffortDuration> rightSlice = interval
.getRightSlice(durationsByDay);
AvailabilityTimeLine availability = getAvailability();
createAssignments(interval, availability,
rightSlice.toArray(new EffortDuration[0]));
}
};
}
@ -842,6 +866,11 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
public void allocateHours(int hours) {
allocateTheWholeAllocation(interval, hours(hours));
}
@Override
public void allocate(List<EffortDuration> durationsByDay) {
allocateDurationsByDay(interval, durationsByDay);
}
};
}
@ -863,24 +892,31 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
private List<T> createAssignments(AllocationInterval interval,
EffortDuration durationToAssign) {
List<T> assignmentsCreated = new ArrayList<T>();
AvailabilityTimeLine availability = getAvailability();
List<PartialDay> days = getDays(interval.getStartInclusive(),
Iterable<PartialDay> days = getDays(interval.getStartInclusive(),
interval.getEndExclusive());
EffortDuration[] durationsEachDay = secondsDistribution(
availability, days, durationToAssign);
return createAssignments(interval, availability, durationsEachDay);
}
private List<T> createAssignments(AllocationInterval interval,
AvailabilityTimeLine availability,
EffortDuration[] durationsEachDay) {
List<T> result = new ArrayList<T>();
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<T extends DayAssignment> extends
}
private EffortDuration[] secondsDistribution(
AvailabilityTimeLine availability, List<PartialDay> days,
AvailabilityTimeLine availability, Iterable<PartialDay> days,
EffortDuration duration) {
List<Share> shares = new ArrayList<Share>();
for (PartialDay each : days) {
@ -985,11 +1021,18 @@ public abstract class ResourceAllocation<T extends DayAssignment> 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<T extends DayAssignment> 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<EffortDuration> getRightSlice(List<EffortDuration> original) {
List<EffortDuration> result = new ArrayList<EffortDuration>(
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<T> 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<T extends DayAssignment> extends
AllocationIntervalInsideTask(IntraDayDate startInclusive,
IntraDayDate endExclusive) {
super(IntraDayDate.max(startInclusive, getTask()
super(startInclusive, endExclusive, IntraDayDate.max(
startInclusive, getTask()
.getFirstDayNotConsolidated()), IntraDayDate.min(
endExclusive, task.getIntraDayEndDate()));
}

View file

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

View file

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