ItEr49S04ValidacionEProbasFuncionaisItEr48S04: Improving allocation correctness.
Taking into account the availability of the resources when distributing some hours in a interval of dates. This way if at a day no hours can be assigned because it doesn't match the criteria or it's a holiday for the resource no hours are assigned. If in the interval there are no days in which could be assigned hours, no assignments are created.
This commit is contained in:
parent
6a4e16a17c
commit
2a46cbddfd
6 changed files with 66 additions and 9 deletions
|
|
@ -67,8 +67,8 @@ public class AvailabilityCalculator {
|
|||
Collection<? extends Criterion> criterions, Resource resource) {
|
||||
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
|
||||
for (Criterion each : criterions) {
|
||||
result = result.and(buildTimeline(resource.query().from(each)
|
||||
.result()));
|
||||
result = result.and(buildTimeline(resource
|
||||
.getSatisfactionsFor(each)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import java.util.Set;
|
|||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
|
||||
import org.navalplanner.business.calendars.entities.IWorkHours;
|
||||
import org.navalplanner.business.planner.entities.HoursDistributor.IResourceSelector;
|
||||
import org.navalplanner.business.planner.entities.HoursDistributor.ResourceWithAssignedHours;
|
||||
|
|
@ -152,10 +153,11 @@ public class GenericResourceAllocation extends
|
|||
|
||||
private class GenericAllocation extends AssignmentsAllocation {
|
||||
|
||||
|
||||
private HoursDistributor hoursDistributor;
|
||||
private final List<Resource> resources;
|
||||
|
||||
public GenericAllocation(List<Resource> resources) {
|
||||
this.resources = resources;
|
||||
hoursDistributor = new HoursDistributor(resources,
|
||||
getAssignedHoursForResource(),
|
||||
new ResourcesSatisfyingCriterionsSelector());
|
||||
|
|
@ -173,6 +175,12 @@ public class GenericResourceAllocation extends
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AvailabilityTimeLine getResourcesAvailability() {
|
||||
return AvailabilityCalculator.buildSumOfAvailabilitiesFor(
|
||||
getCriterions(), resources);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private IAssignedHoursForResource assignedHoursCalculatorOverriden = null;
|
||||
|
|
|
|||
|
|
@ -445,22 +445,42 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
|
|||
setResourcesPerDay(calculateResourcesPerDayFromAssignments());
|
||||
}
|
||||
|
||||
protected abstract AvailabilityTimeLine getResourcesAvailability();
|
||||
|
||||
private List<T> createAssignments(LocalDate startInclusive,
|
||||
LocalDate endExclusive, int hours) {
|
||||
Validate.isTrue(hours >= 0);
|
||||
List<T> assignmentsCreated = new ArrayList<T>();
|
||||
if (hours > 0) {
|
||||
AvailabilityTimeLine availability = getAvailability();
|
||||
|
||||
List<LocalDate> days = getDays(startInclusive, endExclusive);
|
||||
int[] hoursEachDay = hoursDistribution(days, hours);
|
||||
int[] hoursEachDay = hoursDistribution(availability, days,
|
||||
hours);
|
||||
int i = 0;
|
||||
for (LocalDate day : days) {
|
||||
assignmentsCreated.addAll(distributeForDay(day,
|
||||
hoursEachDay[i++]));
|
||||
// if all days are not available, it would try to assign
|
||||
// them anyway, preventing it with a check
|
||||
if (availability.isValid(day)) {
|
||||
assignmentsCreated.addAll(distributeForDay(day,
|
||||
hoursEachDay[i]));
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return onlyNonZeroHours(assignmentsCreated);
|
||||
}
|
||||
|
||||
private AvailabilityTimeLine getAvailability() {
|
||||
AvailabilityTimeLine resourcesAvailability = getResourcesAvailability();
|
||||
if (getTaskCalendar() != null) {
|
||||
return getTaskCalendar().getAvailability().and(
|
||||
resourcesAvailability);
|
||||
} else {
|
||||
return resourcesAvailability;
|
||||
}
|
||||
}
|
||||
|
||||
private List<T> onlyNonZeroHours(List<T> assignmentsCreated) {
|
||||
List<T> result = new ArrayList<T>();
|
||||
for (T each : assignmentsCreated) {
|
||||
|
|
@ -471,17 +491,28 @@ public abstract class ResourceAllocation<T extends DayAssignment> extends
|
|||
return result;
|
||||
}
|
||||
|
||||
private int[] hoursDistribution(List<LocalDate> days, int hoursToSum) {
|
||||
private int[] hoursDistribution(AvailabilityTimeLine availability,
|
||||
List<LocalDate> days, int hoursToSum) {
|
||||
List<Share> shares = new ArrayList<Share>();
|
||||
for (LocalDate day : days) {
|
||||
shares.add(new Share(-getWorkHoursPerDay()
|
||||
.getCapacityAt(day)));
|
||||
shares.add(getShareAt(day, availability));
|
||||
}
|
||||
ShareDivision original = ShareDivision.create(shares);
|
||||
ShareDivision newShare = original.plus(hoursToSum);
|
||||
return original.to(newShare);
|
||||
}
|
||||
|
||||
private Share getShareAt(LocalDate day,
|
||||
AvailabilityTimeLine availability) {
|
||||
if (availability.isValid(day)) {
|
||||
Integer capacityAtDay = getWorkHoursPerDay()
|
||||
.getCapacityAt(day);
|
||||
return new Share(-capacityAtDay);
|
||||
} else {
|
||||
return new Share(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract List<T> distributeForDay(LocalDate day,
|
||||
int totalHours);
|
||||
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import java.util.Set;
|
|||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
|
||||
import org.navalplanner.business.calendars.entities.CombinedWorkHours;
|
||||
import org.navalplanner.business.calendars.entities.IWorkHours;
|
||||
import org.navalplanner.business.planner.entities.allocationalgorithms.HoursModification;
|
||||
|
|
@ -142,6 +143,11 @@ public class SpecificResourceAllocation extends
|
|||
return Arrays.asList(SpecificDayAssignment.create(day,
|
||||
totalHours, resource));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AvailabilityTimeLine getResourcesAvailability() {
|
||||
return AvailabilityCalculator.getCalendarAvailabilityFor(resource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import org.joda.time.Interval;
|
|||
import org.joda.time.LocalDate;
|
||||
import org.joda.time.Period;
|
||||
import org.junit.Test;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
|
||||
import org.navalplanner.business.calendars.entities.BaseCalendar;
|
||||
import org.navalplanner.business.calendars.entities.ResourceCalendar;
|
||||
import org.navalplanner.business.calendars.entities.SameWorkHoursEveryDay;
|
||||
|
|
@ -54,6 +55,8 @@ import org.navalplanner.business.planner.entities.GenericResourceAllocation;
|
|||
import org.navalplanner.business.planner.entities.ResourcesPerDay;
|
||||
import org.navalplanner.business.planner.entities.Task;
|
||||
import org.navalplanner.business.resources.entities.Criterion;
|
||||
import org.navalplanner.business.resources.entities.CriterionSatisfaction;
|
||||
import org.navalplanner.business.resources.entities.ICriterion;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
import org.navalplanner.business.resources.entities.VirtualWorker;
|
||||
import org.navalplanner.business.resources.entities.Worker;
|
||||
|
|
@ -151,6 +154,8 @@ public class GenericResourceAllocationTest {
|
|||
expect(
|
||||
result.getAssignedHoursDiscounting(isA(Object.class),
|
||||
isA(LocalDate.class))).andReturn(hours).anyTimes();
|
||||
expect(result.getSatisfactionsFor(isA(ICriterion.class))).andReturn(
|
||||
new ArrayList<CriterionSatisfaction>()).anyTimes();
|
||||
replay(result);
|
||||
return result;
|
||||
}
|
||||
|
|
@ -210,6 +215,8 @@ public class GenericResourceAllocationTest {
|
|||
}).anyTimes();
|
||||
expect(baseCalendar.canWork(isA(LocalDate.class))).andReturn(true)
|
||||
.anyTimes();
|
||||
expect(baseCalendar.getAvailability()).andReturn(
|
||||
AvailabilityTimeLine.allValid()).anyTimes();
|
||||
if (baseCalendar instanceof ResourceCalendar) {
|
||||
ResourceCalendar resourceCalendar = (ResourceCalendar) baseCalendar;
|
||||
expect(resourceCalendar.getCapacity()).andReturn(1);
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.easymock.IAnswer;
|
|||
import org.easymock.classextension.EasyMock;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Test;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
|
||||
import org.navalplanner.business.calendars.entities.BaseCalendar;
|
||||
import org.navalplanner.business.calendars.entities.ResourceCalendar;
|
||||
import org.navalplanner.business.planner.entities.ResourcesPerDay;
|
||||
|
|
@ -74,6 +75,8 @@ public class SpecificResourceAllocationTest {
|
|||
expect(this.calendar.toHours(isA(LocalDate.class),
|
||||
isA(ResourcesPerDay.class))).andAnswer(
|
||||
toHoursAnswer(hours)).anyTimes();
|
||||
expect(this.calendar.getAvailability()).andReturn(
|
||||
AvailabilityTimeLine.allValid()).anyTimes();
|
||||
replay(this.calendar);
|
||||
}
|
||||
|
||||
|
|
@ -120,6 +123,8 @@ public class SpecificResourceAllocationTest {
|
|||
return toHoursAnswer(hours).answer();
|
||||
}
|
||||
}).anyTimes();
|
||||
expect(this.calendar.getAvailability()).andReturn(
|
||||
AvailabilityTimeLine.allValid()).anyTimes();
|
||||
replay(this.calendar);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue