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:
Óscar González Fernández 2010-03-03 17:05:30 +01:00
parent 6a4e16a17c
commit 2a46cbddfd
6 changed files with 66 additions and 9 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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