Add possibility of specifying new invalid dates
The invalid ranges mechanism is not suitable when the invalid dates to specify are potentially infinite. An additional mechanism is added allowing to veto some of the dates. FEA: ItEr68OTS05IntroducionLimiteSobreasignacionCalendarios
This commit is contained in:
parent
76fcb59dad
commit
bb16e8346c
4 changed files with 142 additions and 4 deletions
|
|
@ -333,6 +333,10 @@ public class AvailabilityTimeLine {
|
|||
}
|
||||
}
|
||||
|
||||
public interface IVetoer {
|
||||
public boolean isValid(LocalDate date);
|
||||
}
|
||||
|
||||
public static AvailabilityTimeLine allValid() {
|
||||
return new AvailabilityTimeLine();
|
||||
}
|
||||
|
|
@ -343,18 +347,31 @@ public class AvailabilityTimeLine {
|
|||
return result;
|
||||
}
|
||||
|
||||
private static IVetoer NO_VETOER = new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private IVetoer vetoer = NO_VETOER;
|
||||
|
||||
private List<Interval> invalids = new ArrayList<Interval>();
|
||||
|
||||
private AvailabilityTimeLine() {
|
||||
}
|
||||
|
||||
public boolean isValid(LocalDate date) {
|
||||
return isValidBasedOnInvaidIntervals(date) && vetoer.isValid(date);
|
||||
}
|
||||
|
||||
private boolean isValidBasedOnInvaidIntervals(LocalDate date) {
|
||||
if (invalids.isEmpty()) {
|
||||
return true;
|
||||
}
|
||||
Interval possibleInterval = findPossibleIntervalFor(date);
|
||||
return (possibleInterval == null || !possibleInterval.includes(date))
|
||||
&& additionalRestriction.isValid(date);
|
||||
return possibleInterval == null || !possibleInterval.includes(date);
|
||||
}
|
||||
|
||||
private Interval findPossibleIntervalFor(LocalDate date) {
|
||||
|
|
@ -380,6 +397,19 @@ public class AvailabilityTimeLine {
|
|||
insert(point);
|
||||
}
|
||||
|
||||
/**
|
||||
* There are some invalid dates that cannot or are not suitable to be
|
||||
* represented as belonging to invalid intervals. For example if the invalid
|
||||
* dates are an infinite set.
|
||||
*
|
||||
* @param vetoer
|
||||
* the vetoer to use
|
||||
*/
|
||||
public void setVetoer(IVetoer vetoer) {
|
||||
Validate.notNull(vetoer);
|
||||
this.vetoer = vetoer;
|
||||
}
|
||||
|
||||
private void insert(Interval toBeInserted) {
|
||||
if (invalids.isEmpty()) {
|
||||
invalids.add(toBeInserted);
|
||||
|
|
@ -481,9 +511,20 @@ public class AvailabilityTimeLine {
|
|||
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
|
||||
inserting(result, invalids);
|
||||
inserting(result, another.invalids);
|
||||
result.setVetoer(and(this.vetoer, another.vetoer));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IVetoer and(final IVetoer a,
|
||||
final IVetoer b) {
|
||||
return new IVetoer() {
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return a.isValid(date) && b.isValid(date);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public AvailabilityTimeLine or(AvailabilityTimeLine another) {
|
||||
List<Interval> intersections = doIntersections(this, another);
|
||||
AvailabilityTimeLine result = AvailabilityTimeLine.allValid();
|
||||
|
|
@ -502,9 +543,20 @@ public class AvailabilityTimeLine {
|
|||
FixedPoint.tryExtract(each.getEnd()));
|
||||
}
|
||||
}
|
||||
result.setVetoer(or(this.vetoer, another.vetoer));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IVetoer or(final IVetoer a,
|
||||
final IVetoer b) {
|
||||
return new IVetoer() {
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return a.isValid(date) || b.isValid(date);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static List<Interval> doIntersections(AvailabilityTimeLine one,
|
||||
AvailabilityTimeLine another) {
|
||||
List<Interval> result = new ArrayList<Interval>();
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import org.hibernate.validator.NotNull;
|
|||
import org.hibernate.validator.Valid;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.calendars.daos.IBaseCalendarDAO;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.IVetoer;
|
||||
import org.navalplanner.business.calendars.entities.CalendarData.Days;
|
||||
import org.navalplanner.business.common.IntegrationEntity;
|
||||
import org.navalplanner.business.common.entities.EntitySequence;
|
||||
|
|
@ -789,10 +790,23 @@ public class BaseCalendar extends IntegrationEntity implements ICalendar {
|
|||
private void addInvaliditiesDerivedFromCalendar(AvailabilityTimeLine result) {
|
||||
addInvaliditiesFromAvailabilities(result);
|
||||
addInvaliditiesFromExceptions(result);
|
||||
addInvaliditiesFromCalendarDatas(result);
|
||||
addInvaliditiesFromEmptyCalendarDatas(result);
|
||||
addInvaliditiesFromEmptyDaysInCalendarDatas(result);
|
||||
}
|
||||
|
||||
private void addInvaliditiesFromCalendarDatas(AvailabilityTimeLine result) {
|
||||
private void addInvaliditiesFromEmptyDaysInCalendarDatas(
|
||||
AvailabilityTimeLine result) {
|
||||
result.setVetoer(new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return canWorkOn(date);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void addInvaliditiesFromEmptyCalendarDatas(
|
||||
AvailabilityTimeLine result) {
|
||||
LocalDate previous = null;
|
||||
for (CalendarData each : calendarDataVersions) {
|
||||
addInvalidityIfDataEmpty(result, previous, each);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
package org.navalplanner.business.test.calendars.entities;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
|
@ -38,6 +39,7 @@ import org.navalplanner.business.calendars.entities.AvailabilityTimeLine;
|
|||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.DatePoint;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.EndOfTime;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.FixedPoint;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.IVetoer;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.Interval;
|
||||
import org.navalplanner.business.calendars.entities.AvailabilityTimeLine.StartOfTime;
|
||||
|
||||
|
|
@ -300,6 +302,36 @@ public class AvailabilityTimeLineTest {
|
|||
.plusDays(20)), EndOfTime.create()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doingAnORDoesAnOrForAdditionalConstraints() {
|
||||
boolean[][] validities = { { true, true }, { true, false },
|
||||
{ false, true }, { false, false } };
|
||||
for (final boolean[] pairs : validities) {
|
||||
AvailabilityTimeLine a = AvailabilityTimeLine.allValid();
|
||||
a.setVetoer(new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return pairs[0];
|
||||
}
|
||||
});
|
||||
AvailabilityTimeLine b = AvailabilityTimeLine.allValid();
|
||||
b.setVetoer(new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return pairs[1];
|
||||
}
|
||||
});
|
||||
AvailabilityTimeLine result = a.or(b);
|
||||
boolean expected = pairs[0] || pairs[1];
|
||||
|
||||
assertThat(result.isValid(earlyExample), equalTo(expected));
|
||||
assertThat(result.isValid(contemporaryExample), equalTo(expected));
|
||||
assertThat(result.isValid(lateExample), equalTo(expected));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doingAnAndWithAnAllValidTimeLineProducesTheSameTimeLine() {
|
||||
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();
|
||||
|
|
@ -315,6 +347,36 @@ public class AvailabilityTimeLineTest {
|
|||
.plusDays(20)), EndOfTime.create()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doingAnAndIntersectsTheAdditionalConstraints() {
|
||||
boolean[][] validities = { { true, true }, { true, false },
|
||||
{ false, true }, { false, false } };
|
||||
for (final boolean[] pairs : validities) {
|
||||
AvailabilityTimeLine a = AvailabilityTimeLine.allValid();
|
||||
a.setVetoer(new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return pairs[0];
|
||||
}
|
||||
});
|
||||
AvailabilityTimeLine b = AvailabilityTimeLine.allValid();
|
||||
b.setVetoer(new IVetoer() {
|
||||
|
||||
@Override
|
||||
public boolean isValid(LocalDate date) {
|
||||
return pairs[1];
|
||||
}
|
||||
});
|
||||
AvailabilityTimeLine result = a.and(b);
|
||||
boolean expected = pairs[0] && pairs[1];
|
||||
|
||||
assertThat(result.isValid(earlyExample), equalTo(expected));
|
||||
assertThat(result.isValid(contemporaryExample), equalTo(expected));
|
||||
assertThat(result.isValid(lateExample), equalTo(expected));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doingAnOrWithANeverValidTimeLineProducesTheSameTimeLine() {
|
||||
AvailabilityTimeLine timeLine = AvailabilityTimeLine.allValid();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import java.util.Set;
|
|||
|
||||
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.BaseCalendar.DayType;
|
||||
import org.navalplanner.business.calendars.entities.CalendarData.Days;
|
||||
|
|
@ -909,4 +910,13 @@ public class BaseCalendarTest {
|
|||
assertFalse(calendar.canWorkOn(MONDAY_LOCAL_DATE));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void theAvailabilityTimeLineTakesIntoAccountTheDaysItCannotWorkDueToCalendarData() {
|
||||
BaseCalendar calendar = createBasicCalendar();
|
||||
calendar.setCapacityAt(Days.MONDAY, Capacity.create(hours(0))
|
||||
.overAssignableWithoutLimit(false));
|
||||
|
||||
AvailabilityTimeLine availability = calendar.getAvailability();
|
||||
assertFalse(availability.isValid(MONDAY_LOCAL_DATE));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue