Add method for specifying several days together in an interval
FEA: ItEr74S04BugFixing
This commit is contained in:
parent
8520456ad8
commit
4063b6d293
4 changed files with 187 additions and 21 deletions
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue