Add getCapacityWithOvertime to ICalendar

This method is needed to distribute the load among resources taking
into account the overtime.

FEA: ItEr71S07FragmentationDeletionItEr70S09
This commit is contained in:
Óscar González Fernández 2011-02-22 16:58:16 +01:00
parent 219b3c1f16
commit c24fe5a615
7 changed files with 126 additions and 22 deletions

View file

@ -31,6 +31,7 @@ import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.hibernate.validator.AssertTrue;
import org.hibernate.validator.NotEmpty;
import org.hibernate.validator.NotNull;
@ -42,6 +43,7 @@ import org.navalplanner.business.calendars.entities.CalendarData.Days;
import org.navalplanner.business.common.IntegrationEntity;
import org.navalplanner.business.common.entities.EntitySequence;
import org.navalplanner.business.common.exceptions.InstanceNotFoundException;
import org.navalplanner.business.resources.entities.VirtualWorker;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.ResourcesPerDay;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;
@ -265,10 +267,16 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar {
}
public EffortDuration getCapacityOn(PartialDay date) {
return date.limitDuration(findCapacityAt(date.getDate())
return date.limitDuration(getCapacityWithOvertime(date.getDate())
.getStandardEffort());
}
@Override
public Capacity getCapacityWithOvertime(LocalDate day) {
Validate.notNull(day);
return multiplyByCalendarUnits(findCapacityAt(day));
}
private Capacity findCapacityAt(LocalDate date) {
if (!isActive(date)) {
return Capacity.zero();
@ -759,14 +767,22 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar {
.getStandardEffort());
EffortDuration asDuration = amount
.asDurationGivenWorkingDayOf(workableDuration);
return capacity.limitDuration(asDuration);
return multiplyByCalendarUnits(capacity).limitDuration(asDuration);
}
/**
* This method is intended to be overriden
* <p>
* Calendar units are the number of units this calendar is applied to. For
* example a {@link VirtualWorker} composed of ten workers would multiply
* the capacity by ten.
* </p>
* <p>
* This method is intended to be overridden
* </p>
*
*/
protected EffortDuration multiplyByCapacity(EffortDuration duration) {
return duration;
protected Capacity multiplyByCalendarUnits(Capacity capacity) {
return capacity;
}
@Override
@ -996,4 +1012,5 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar {
public Integer getLastSequenceCode() {
return lastSequenceCode;
}
}

View file

@ -31,6 +31,7 @@ import java.util.Collections;
import java.util.List;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;
import org.navalplanner.business.workingday.ResourcesPerDay;
@ -92,6 +93,16 @@ public abstract class CombinedWorkHours implements ICalendar {
return result;
}
@Override
public Capacity getCapacityWithOvertime(LocalDate day) {
Capacity result = null;
for (ICalendar each : calendars) {
Capacity current = each.getCapacityWithOvertime(day);
result = result == null ? current : updateCapacity(result, current);
}
return result;
}
@Override
public AvailabilityTimeLine getAvailability() {
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
@ -110,6 +121,8 @@ public abstract class CombinedWorkHours implements ICalendar {
protected abstract EffortDuration updateCapacity(EffortDuration current,
EffortDuration each);
protected abstract Capacity updateCapacity(Capacity a, Capacity current);
@Override
public boolean thereAreCapacityFor(AvailabilityTimeLine availability,
ResourcesPerDay resourcesPerDay, EffortDuration durationToAllocate) {
@ -143,6 +156,11 @@ class Min extends CombinedWorkHours {
return accumulated.and(each);
}
@Override
protected Capacity updateCapacity(Capacity accumulated, Capacity current) {
return Capacity.min(accumulated, current);
}
}
class Max extends CombinedWorkHours {
@ -168,4 +186,9 @@ class Max extends CombinedWorkHours {
AvailabilityTimeLine accumulated, AvailabilityTimeLine each) {
return accumulated.or(each);
}
@Override
protected Capacity updateCapacity(Capacity accumulated, Capacity current) {
return Capacity.max(accumulated, current);
}
}

View file

@ -21,6 +21,7 @@
package org.navalplanner.business.calendars.entities;
import org.joda.time.LocalDate;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;
import org.navalplanner.business.workingday.ResourcesPerDay;
@ -48,6 +49,17 @@ public interface ICalendar {
*/
public EffortDuration getCapacityOn(PartialDay partialDay);
/**
* Calculates the capacity information for a given date. It contains
* information about the normal effort and the extra effort, i.e., the
* overtime effort.
*
* @param date
* a not null date
* @return the capacity for the date provided
*/
public Capacity getCapacityWithOvertime(LocalDate date);
public AvailabilityTimeLine getAvailability();
public boolean thereAreCapacityFor(AvailabilityTimeLine availability,

View file

@ -84,18 +84,8 @@ public class ResourceCalendar extends BaseCalendar {
}
@Override
public EffortDuration getCapacityOn(PartialDay date) {
return multiplyByCapacity(super.getCapacityOn(date));
}
protected EffortDuration multiplyByCapacity(EffortDuration duration) {
if (duration == null) {
return EffortDuration.zero();
}
if (capacity == null) {
return duration;
}
return duration.multiplyBy(capacity);
protected Capacity multiplyByCalendarUnits(Capacity capacity) {
return capacity.multiplyBy(getCapacity());
}
@AssertTrue(message = "Capacity must be a positive integer number")

View file

@ -22,6 +22,7 @@
package org.navalplanner.business.calendars.entities;
import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;
import org.navalplanner.business.workingday.ResourcesPerDay;
@ -44,7 +45,8 @@ public class SameWorkHoursEveryDay implements ICalendar {
@Override
public EffortDuration getCapacityOn(PartialDay partialDay) {
return partialDay.limitDuration(EffortDuration.hours(hours));
return partialDay.limitDuration(getCapacityWithOvertime(
partialDay.getDate()).getStandardEffort());
}
@Override
@ -63,4 +65,10 @@ public class SameWorkHoursEveryDay implements ICalendar {
return AvailabilityTimeLine.allValid();
}
@Override
public Capacity getCapacityWithOvertime(LocalDate day) {
return Capacity.create(EffortDuration.hours(hours))
.overAssignableWithoutLimit(true);
}
}

View file

@ -801,6 +801,23 @@ public class BaseCalendarTest {
ResourcesPerDay.amount(2)), equalTo(hours(16)));
}
@Test(expected = IllegalArgumentException.class)
public void getCapacityWithOvertimeMustNotBeCalledWithANullDate() {
BaseCalendar calendar = createBasicCalendar();
calendar.getCapacityWithOvertime(null);
}
@Test
public void getCapacityWithOvertimeOnReturnsTheCapacityForThatDay() {
BaseCalendar calendar = createBasicCalendar();
Capacity capacitySet = Capacity.create(hours(8))
.overAssignableWithoutLimit(true);
calendar.setCapacityAt(Days.MONDAY, capacitySet);
assertThat(calendar.getCapacityWithOvertime(MONDAY_LOCAL_DATE),
equalTo(capacitySet));
}
@Test
public void asDurationOnRespectsTheNotOverAssignablePropertyOfCalendarData() {
BaseCalendar calendar = createBasicCalendar();

View file

@ -37,6 +37,8 @@ import org.navalplanner.business.calendars.entities.CalendarData.Days;
import org.navalplanner.business.calendars.entities.Capacity;
import org.navalplanner.business.calendars.entities.ResourceCalendar;
import org.navalplanner.business.workingday.EffortDuration;
import org.navalplanner.business.workingday.IntraDayDate.PartialDay;
import org.navalplanner.business.workingday.ResourcesPerDay;
/**
* Tests for {@link ResourceCalendar}.
@ -45,17 +47,23 @@ import org.navalplanner.business.workingday.EffortDuration;
*/
public class ResourceCalendarTest {
public static ResourceCalendar createBasicResourceCalendar() {
private static final Capacity capacityForEveryDay = Capacity.create(
EffortDuration.hours(8)).overAssignableWithoutLimit(true);
public static ResourceCalendar createBasicResourceCalendar(int capacity) {
ResourceCalendar calendar = ResourceCalendar.create();
calendar.setName("Test");
for (Days each : Days.values()) {
calendar.setCapacityAt(each,
Capacity.create(EffortDuration.hours(8))
.overAssignableWithoutLimit(true));
calendar.setCapacityAt(each, capacityForEveryDay);
}
calendar.setCapacity(capacity);
return calendar;
}
public static ResourceCalendar createBasicResourceCalendar() {
return createBasicResourceCalendar(1);
}
private static final LocalDate PAST = (new LocalDate()).minusMonths(1);
private static final LocalDate FUTURE = (new LocalDate()).plusMonths(1);
@ -77,6 +85,35 @@ public class ResourceCalendarTest {
equalTo(EffortDuration.hours(8)));
}
@Test
public void getCapacityWithOverTimeIsMultipliedByTheCapacityOfTheResourceCalendar() {
ResourceCalendar calendar = createBasicResourceCalendar(2);
Capacity capacity = calendar.getCapacityWithOvertime(FUTURE);
assertThat(capacity, equalTo(capacityForEveryDay.multiplyBy(2)));
}
@Test
public void theCapacityEffortIsMultipliedByTheCapacityOfTheResourceCalendar() {
ResourceCalendar calendar = createBasicResourceCalendar(2);
EffortDuration duration = calendar.getCapacityOn(PartialDay
.wholeDay(FUTURE));
assertThat(duration, equalTo(capacityForEveryDay.getStandardEffort()
.multiplyBy(2)));
}
@Test
public void asDurationOnDoesntChangeWithTheCapacityOfTheResourceCalendar() {
ResourceCalendar[] calendars = { createBasicResourceCalendar(),
createBasicResourceCalendar(2), createBasicResourceCalendar(3) };
for (ResourceCalendar each : calendars) {
EffortDuration duration = each.asDurationOn(
PartialDay.wholeDay(FUTURE),
ResourcesPerDay.amount(1));
assertThat(duration,
equalTo(capacityForEveryDay.getStandardEffort()));
}
}
@Test(expected = IllegalArgumentException.class)
public void notAllowCreateCalendarAvailabilityInThePast() {
ResourceCalendar calendar = createBasicResourceCalendar();