Implement ResourceLoadChartData using ContiguousDaysLine
FEA: ItEr75S11PreventLooseChanges
This commit is contained in:
parent
0aa872e1cb
commit
d083daecba
3 changed files with 316 additions and 166 deletions
|
|
@ -18,15 +18,23 @@
|
|||
*/
|
||||
package org.navalplanner.business.planner.chart;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.Days;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.planner.chart.ContiguousDaysLine.ONDay;
|
||||
import org.navalplanner.business.planner.entities.DayAssignment;
|
||||
import org.navalplanner.business.workingday.EffortDuration;
|
||||
|
||||
/**
|
||||
* It represents some contiguous days from a start date to a not included end
|
||||
|
|
@ -75,12 +83,154 @@ public class ContiguousDaysLine<T> implements Iterable<ONDay<T>> {
|
|||
return new ContiguousDaysLine<T>(fromInclusive, daysBetween.getDays());
|
||||
}
|
||||
|
||||
public static ContiguousDaysLine<List<DayAssignment>> byDay(
|
||||
Collection<? extends DayAssignment> assignments) {
|
||||
if (assignments.isEmpty()) {
|
||||
return invalid();
|
||||
}
|
||||
DayAssignment min = Collections.min(assignments,
|
||||
DayAssignment.byDayComparator());
|
||||
DayAssignment max = Collections.max(assignments,
|
||||
DayAssignment.byDayComparator());
|
||||
ContiguousDaysLine<List<DayAssignment>> result = create(min.getDay(),
|
||||
max.getDay().plusDays(1));
|
||||
result.transformInSitu(new IValueTransformer<List<DayAssignment>, List<DayAssignment>>() {
|
||||
|
||||
@Override
|
||||
public List<DayAssignment> transform(LocalDate day,
|
||||
List<DayAssignment> previousValue) {
|
||||
return new LinkedList<DayAssignment>();
|
||||
}
|
||||
});
|
||||
for (DayAssignment each : assignments) {
|
||||
result.get(each.getDay()).add(each);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> ContiguousDaysLine<T> invalid() {
|
||||
return new ContiguousDaysLine<T>(null, 0);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ContiguousDaysLine<EffortDuration> min(
|
||||
ContiguousDaysLine<EffortDuration> a,
|
||||
ContiguousDaysLine<EffortDuration> b) {
|
||||
return join(EffortDuration.class, minTransformer(), a, b);
|
||||
}
|
||||
|
||||
public static IValueTransformer<EffortDuration[], EffortDuration> minTransformer() {
|
||||
return new IValueTransformer<EffortDuration[], EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
EffortDuration[] previousValue) {
|
||||
return EffortDuration.min(previousValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Joins both {@link ContiguousDaysLine} substracting from minuend line. An
|
||||
* effortDuration can't be negative so, if subtrahend line is at some point
|
||||
* bigger than minuend, zero is returned at that point.
|
||||
*
|
||||
* @param minuend
|
||||
* @param subtrahend
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ContiguousDaysLine<EffortDuration> substract(
|
||||
ContiguousDaysLine<EffortDuration> minuend,
|
||||
ContiguousDaysLine<EffortDuration> subtrahend) {
|
||||
return join(EffortDuration.class, substractTransformer(), minuend,
|
||||
subtrahend);
|
||||
}
|
||||
|
||||
private static IValueTransformer<EffortDuration[], EffortDuration> substractTransformer() {
|
||||
return new IValueTransformer<EffortDuration[], EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
EffortDuration[] previousValue) {
|
||||
EffortDuration result = previousValue[0];
|
||||
for (int i = 1; i < previousValue.length; i++) {
|
||||
result = result.minus(EffortDuration.min(previousValue[i],
|
||||
result));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static ContiguousDaysLine<EffortDuration> sum(
|
||||
ContiguousDaysLine<EffortDuration> summandA,
|
||||
ContiguousDaysLine<EffortDuration> summandB) {
|
||||
return join(EffortDuration.class, additionTransformer(), summandA,
|
||||
summandB);
|
||||
}
|
||||
|
||||
public static SortedMap<LocalDate, EffortDuration> toSortedMap(
|
||||
ContiguousDaysLine<EffortDuration> line) {
|
||||
SortedMap<LocalDate, EffortDuration> result = new TreeMap<LocalDate, EffortDuration>();
|
||||
for (ONDay<EffortDuration> each : line) {
|
||||
result.put(each.getDay(), each.getValue());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static IValueTransformer<EffortDuration[], EffortDuration> additionTransformer() {
|
||||
return new IValueTransformer<EffortDuration[], EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
EffortDuration[] previousValue) {
|
||||
return EffortDuration.sum(previousValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, R> ContiguousDaysLine<R> join(final Class<T> klass,
|
||||
final IValueTransformer<T[], R> transformer,
|
||||
final ContiguousDaysLine<T>... lines) {
|
||||
if (lines[0].isNotValid()) {
|
||||
return invalid();
|
||||
}
|
||||
LocalDate start = lines[0].getStart();
|
||||
LocalDate endExclusive = lines[0].getEndExclusive();
|
||||
for (ContiguousDaysLine<T> each : lines) {
|
||||
Validate.isTrue(each.getStart().equals(start),
|
||||
"the start of all lines must be same date");
|
||||
Validate.isTrue(each.getEndExclusive().equals(endExclusive),
|
||||
"the start of all lines must be same date");
|
||||
}
|
||||
ContiguousDaysLine<R> result = ContiguousDaysLine.create(start,
|
||||
endExclusive);
|
||||
result.transformInSitu(new IValueTransformer<R, R>() {
|
||||
|
||||
@Override
|
||||
public R transform(LocalDate day, R previousValue) {
|
||||
return transformer.transform(day, getValues(day, lines));
|
||||
}
|
||||
|
||||
private T[] getValues(LocalDate day, ContiguousDaysLine<T>... lines) {
|
||||
@SuppressWarnings("unchecked")
|
||||
T[] result = (T[]) Array.newInstance(klass, lines.length);
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = lines[i].get(day);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
private final LocalDate startInclusive;
|
||||
|
||||
private final List<T> values;
|
||||
|
||||
private ContiguousDaysLine(LocalDate start, int size) {
|
||||
Validate.notNull(start);
|
||||
this.startInclusive = start;
|
||||
this.values = new ArrayList<T>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
|
@ -88,12 +238,23 @@ public class ContiguousDaysLine<T> implements Iterable<ONDay<T>> {
|
|||
}
|
||||
}
|
||||
|
||||
public boolean isNotValid() {
|
||||
return startInclusive == null;
|
||||
}
|
||||
|
||||
public LocalDate getStart() {
|
||||
mustBeValid();
|
||||
return startInclusive;
|
||||
}
|
||||
|
||||
private void mustBeValid() {
|
||||
if (isNotValid()) {
|
||||
throw new IllegalStateException("this line is invalid");
|
||||
}
|
||||
}
|
||||
|
||||
public LocalDate getEndExclusive() {
|
||||
return startInclusive.plusDays(values.size());
|
||||
return getStart().plusDays(values.size());
|
||||
}
|
||||
|
||||
public T get(LocalDate day) throws IndexOutOfBoundsException {
|
||||
|
|
@ -137,6 +298,9 @@ public class ContiguousDaysLine<T> implements Iterable<ONDay<T>> {
|
|||
|
||||
public <R> ContiguousDaysLine<R> transform(
|
||||
IValueTransformer<T, R> doubleTransformer) {
|
||||
if (isNotValid()) {
|
||||
return invalid();
|
||||
}
|
||||
ContiguousDaysLine<R> result = ContiguousDaysLine.create(
|
||||
startInclusive, getEndExclusive());
|
||||
for (ONDay<T> onDay : this) {
|
||||
|
|
@ -146,6 +310,34 @@ public class ContiguousDaysLine<T> implements Iterable<ONDay<T>> {
|
|||
return result;
|
||||
}
|
||||
|
||||
public ContiguousDaysLine<T> copy() {
|
||||
return transform(ContiguousDaysLine.<T> identity());
|
||||
}
|
||||
|
||||
private static <T> IValueTransformer<T, T> identity() {
|
||||
return new IValueTransformer<T, T>() {
|
||||
|
||||
@Override
|
||||
public T transform(LocalDate day, T previousValue) {
|
||||
return previousValue;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static <T, S, R> IValueTransformer<T, R> compound(
|
||||
final IValueTransformer<T, S> first,
|
||||
final IValueTransformer<S, R> last) {
|
||||
|
||||
return new IValueTransformer<T, R>() {
|
||||
|
||||
@Override
|
||||
public R transform(LocalDate day, T previousValue) {
|
||||
S intermediateValue = first.transform(day, previousValue);
|
||||
return last.transform(day, intermediateValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ONDay<T>> iterator() {
|
||||
final Iterator<T> iterator = values.iterator();
|
||||
|
|
|
|||
|
|
@ -21,21 +21,23 @@
|
|||
|
||||
package org.navalplanner.business.planner.chart;
|
||||
|
||||
import static org.navalplanner.business.planner.chart.ContiguousDaysLine.compound;
|
||||
import static org.navalplanner.business.planner.chart.ContiguousDaysLine.sum;
|
||||
import static org.navalplanner.business.planner.chart.ContiguousDaysLine.toSortedMap;
|
||||
import static org.navalplanner.business.workingday.EffortDuration.min;
|
||||
import static org.navalplanner.business.workingday.EffortDuration.zero;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.navalplanner.business.calendars.entities.ICalendar;
|
||||
import org.navalplanner.business.hibernate.notification.PredefinedDatabaseSnapshots;
|
||||
import org.navalplanner.business.planner.chart.ContiguousDaysLine.IValueTransformer;
|
||||
import org.navalplanner.business.planner.entities.DayAssignment;
|
||||
import org.navalplanner.business.resources.entities.Resource;
|
||||
import org.navalplanner.business.workingday.EffortDuration;
|
||||
|
|
@ -60,25 +62,113 @@ public class ResourceLoadChartData implements ILoadChartData {
|
|||
private SortedMap<LocalDate, EffortDuration> availability;
|
||||
|
||||
public ResourceLoadChartData(List<DayAssignment> dayAssignments, List<Resource> resources) {
|
||||
SortedMap<LocalDate, Map<Resource, EffortDuration>> map =
|
||||
groupDurationsByDayAndResource(dayAssignments);
|
||||
this.load = calculateResourceLoadPerDate(map);
|
||||
this.overload = calculateResourceOverloadPerDate(map);
|
||||
if(load.keySet().isEmpty()) {
|
||||
this.availability = new TreeMap<LocalDate, EffortDuration>();
|
||||
}
|
||||
else {
|
||||
this.availability = calculateAvailabilityDurationByDay(
|
||||
resources, load.firstKey(), load.lastKey());
|
||||
}
|
||||
|
||||
for (LocalDate day : this.overload.keySet()) {
|
||||
EffortDuration overloadDuration = this.overload
|
||||
.get(day);
|
||||
EffortDuration maxDuration = this.availability.get(day);
|
||||
this.overload.put(day,
|
||||
overloadDuration.plus(maxDuration));
|
||||
}
|
||||
ContiguousDaysLine<List<DayAssignment>> assignments = ContiguousDaysLine
|
||||
.byDay(dayAssignments);
|
||||
|
||||
ContiguousDaysLine<EffortDuration> load = assignments
|
||||
.transform(extractLoad());
|
||||
|
||||
ContiguousDaysLine<EffortDuration> overload = assignments
|
||||
.transform(extractOverload());
|
||||
|
||||
ContiguousDaysLine<EffortDuration> availabilityOnAllResources = assignments
|
||||
.transform(extractAvailabilityOnAllResources(resources));
|
||||
|
||||
this.load = toSortedMap(ContiguousDaysLine.min(load,
|
||||
availabilityOnAllResources));
|
||||
this.overload = toSortedMap(sum(overload, availabilityOnAllResources));
|
||||
this.availability = toSortedMap(availabilityOnAllResources);
|
||||
}
|
||||
|
||||
private IValueTransformer<List<DayAssignment>, EffortDuration> extractOverload() {
|
||||
return compound(effortByResource(), calculateOverload());
|
||||
}
|
||||
|
||||
private IValueTransformer<List<DayAssignment>, Map<Resource, EffortDuration>> effortByResource() {
|
||||
return new IValueTransformer<List<DayAssignment>, Map<Resource, EffortDuration>>() {
|
||||
|
||||
@Override
|
||||
public Map<Resource, EffortDuration> transform(LocalDate day,
|
||||
List<DayAssignment> previousValue) {
|
||||
Map<Resource, List<DayAssignment>> byResource = DayAssignment
|
||||
.byResource(previousValue);
|
||||
Map<Resource, EffortDuration> result = new HashMap<Resource, EffortDuration>();
|
||||
for (Entry<Resource, List<DayAssignment>> each : byResource
|
||||
.entrySet()) {
|
||||
result.put(each.getKey(),
|
||||
DayAssignment.sum(each.getValue()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IValueTransformer<Map<Resource, EffortDuration>, EffortDuration> calculateOverload() {
|
||||
return new IValueTransformer<Map<Resource, EffortDuration>, EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
Map<Resource, EffortDuration> previousValue) {
|
||||
|
||||
final PartialDay wholeDay = PartialDay.wholeDay(day);
|
||||
return EffortDuration.sum(previousValue.entrySet(),
|
||||
new IEffortFrom<Entry<Resource, EffortDuration>>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration from(
|
||||
Entry<Resource, EffortDuration> each) {
|
||||
EffortDuration capacity = calendarCapacityFor(
|
||||
each.getKey(), wholeDay);
|
||||
EffortDuration assigned = each.getValue();
|
||||
return assigned.minus(min(capacity, assigned));
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IValueTransformer<List<DayAssignment>, EffortDuration> extractLoad() {
|
||||
return new IValueTransformer<List<DayAssignment>, EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
List<DayAssignment> previousValue) {
|
||||
return DayAssignment.sum(previousValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IValueTransformer<List<DayAssignment>, EffortDuration> extractAvailabilityOnAssignedResources() {
|
||||
return new IValueTransformer<List<DayAssignment>, EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
List<DayAssignment> previousValue) {
|
||||
Set<Resource> resources = getResources(previousValue);
|
||||
return sumCalendarCapacitiesForDay(resources, day);
|
||||
}
|
||||
|
||||
private Set<Resource> getResources(List<DayAssignment> assignments) {
|
||||
Set<Resource> resources = new HashSet<Resource>();
|
||||
for (DayAssignment dayAssignment : assignments) {
|
||||
resources.add(dayAssignment.getResource());
|
||||
}
|
||||
return resources;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private IValueTransformer<List<DayAssignment>, EffortDuration> extractAvailabilityOnAllResources(
|
||||
final List<Resource> resources) {
|
||||
return new IValueTransformer<List<DayAssignment>, EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration transform(LocalDate day,
|
||||
List<DayAssignment> previousValue) {
|
||||
return sumCalendarCapacitiesForDay(resources, day);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public SortedMap<LocalDate, EffortDuration> getLoad() {
|
||||
|
|
@ -130,140 +220,7 @@ public class ResourceLoadChartData implements ILoadChartData {
|
|||
};
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, Map<Resource, EffortDuration>> groupDurationsByDayAndResource(
|
||||
List<DayAssignment> dayAssignments) {
|
||||
SortedMap<LocalDate, Map<Resource, EffortDuration>> map =
|
||||
new TreeMap<LocalDate, Map<Resource, EffortDuration>>();
|
||||
|
||||
for (DayAssignment dayAssignment : dayAssignments) {
|
||||
final LocalDate day = dayAssignment.getDay();
|
||||
final EffortDuration dayAssignmentDuration = dayAssignment
|
||||
.getDuration();
|
||||
Resource resource = dayAssignment.getResource();
|
||||
if (map.get(day) == null) {
|
||||
map.put(day, new HashMap<Resource, EffortDuration>());
|
||||
}
|
||||
Map<Resource, EffortDuration> forDay = map.get(day);
|
||||
EffortDuration previousDuration = forDay.get(resource);
|
||||
previousDuration = previousDuration != null ? previousDuration
|
||||
: EffortDuration.zero();
|
||||
forDay.put(dayAssignment.getResource(),
|
||||
previousDuration.plus(dayAssignmentDuration));
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, EffortDuration> calculateResourceLoadPerDate(
|
||||
SortedMap<LocalDate, Map<Resource, EffortDuration>> durationsGrouped) {
|
||||
SortedMap<LocalDate, EffortDuration> map = new TreeMap<LocalDate, EffortDuration>();
|
||||
|
||||
for (LocalDate date : durationsGrouped.keySet()) {
|
||||
EffortDuration result = zero();
|
||||
PartialDay day = PartialDay.wholeDay(date);
|
||||
for (Resource resource : durationsGrouped.get(date).keySet()) {
|
||||
ICalendar calendar = resource.getCalendarOrDefault();
|
||||
EffortDuration workableTime = calendar.getCapacityOn(day);
|
||||
EffortDuration assignedDuration = durationsGrouped.get(
|
||||
day.getDate()).get(resource);
|
||||
result = result.plus(min(assignedDuration, workableTime));
|
||||
}
|
||||
|
||||
map.put(date, result);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
protected abstract class EffortByDayCalculator<T> {
|
||||
public SortedMap<LocalDate, EffortDuration> calculate(
|
||||
Collection<? extends T> elements) {
|
||||
SortedMap<LocalDate, EffortDuration> result = new TreeMap<LocalDate, EffortDuration>();
|
||||
if (elements.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
for (T element : elements) {
|
||||
if (included(element)) {
|
||||
EffortDuration duration = getDurationFor(element);
|
||||
LocalDate day = getDayFor(element);
|
||||
EffortDuration previous = result.get(day);
|
||||
previous = previous == null ? zero() : previous;
|
||||
result.put(day, previous.plus(duration));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected abstract LocalDate getDayFor(T element);
|
||||
|
||||
protected abstract EffortDuration getDurationFor(T element);
|
||||
|
||||
protected boolean included(T each) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, EffortDuration> calculateResourceOverloadPerDate(
|
||||
SortedMap<LocalDate, Map<Resource, EffortDuration>> dayAssignmentGrouped) {
|
||||
return new EffortByDayCalculator<Entry<LocalDate, Map<Resource, EffortDuration>>>() {
|
||||
|
||||
@Override
|
||||
protected LocalDate getDayFor(
|
||||
Entry<LocalDate, Map<Resource, EffortDuration>> element) {
|
||||
return element.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EffortDuration getDurationFor(
|
||||
Entry<LocalDate, Map<Resource, EffortDuration>> element) {
|
||||
|
||||
final PartialDay day = PartialDay.wholeDay(element.getKey());
|
||||
|
||||
return EffortDuration.sum(element.getValue().entrySet(),
|
||||
new IEffortFrom<Entry<Resource, EffortDuration>>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration from(
|
||||
Entry<Resource, EffortDuration> each) {
|
||||
EffortDuration overload = getOverloadAt(day,
|
||||
each.getKey(), each.getValue());
|
||||
return overload;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private EffortDuration getOverloadAt(PartialDay day,
|
||||
Resource resource, EffortDuration assignedDuration) {
|
||||
ICalendar calendar = resource.getCalendarOrDefault();
|
||||
EffortDuration workableDuration = calendar
|
||||
.getCapacityOn(day);
|
||||
if (assignedDuration.compareTo(workableDuration) > 0) {
|
||||
return assignedDuration.minus(workableDuration);
|
||||
}
|
||||
return zero();
|
||||
}
|
||||
}.calculate(dayAssignmentGrouped.entrySet());
|
||||
}
|
||||
|
||||
private SortedMap<LocalDate, EffortDuration> calculateAvailabilityDurationByDay(
|
||||
final List<Resource> resources, LocalDate start, LocalDate finish) {
|
||||
return new EffortByDayCalculator<Entry<LocalDate, List<Resource>>>() {
|
||||
|
||||
@Override
|
||||
protected LocalDate getDayFor(
|
||||
Entry<LocalDate, List<Resource>> element) {
|
||||
return element.getKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected EffortDuration getDurationFor(
|
||||
Entry<LocalDate, List<Resource>> element) {
|
||||
LocalDate day = element.getKey();
|
||||
return sumCalendarCapacitiesForDay(resources, day);
|
||||
}
|
||||
|
||||
}.calculate(getResourcesByDateBetween(resources, start, finish));
|
||||
}
|
||||
|
||||
protected static EffortDuration sumCalendarCapacitiesForDay(
|
||||
private static EffortDuration sumCalendarCapacitiesForDay(
|
||||
Collection<? extends Resource> resources, LocalDate day) {
|
||||
|
||||
final PartialDay wholeDay = PartialDay.wholeDay(day);
|
||||
|
|
@ -281,13 +238,4 @@ public class ResourceLoadChartData implements ILoadChartData {
|
|||
return resource.getCalendarOrDefault().getCapacityOn(day);
|
||||
}
|
||||
|
||||
private Set<Entry<LocalDate, List<Resource>>> getResourcesByDateBetween(
|
||||
List<Resource> resources, LocalDate start, LocalDate finish) {
|
||||
Map<LocalDate, List<Resource>> result = new HashMap<LocalDate, List<Resource>>();
|
||||
for (LocalDate date = new LocalDate(start); date.compareTo(finish) <= 0; date = date
|
||||
.plusDays(1)) {
|
||||
result.put(date, resources);
|
||||
}
|
||||
return result.entrySet();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,16 @@ public class EffortDuration implements Comparable<EffortDuration> {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static EffortDuration sum(EffortDuration... summands) {
|
||||
return sum(Arrays.asList(summands), new IEffortFrom<EffortDuration>() {
|
||||
|
||||
@Override
|
||||
public EffortDuration from(EffortDuration each) {
|
||||
return each;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static EffortDuration zero() {
|
||||
return elapsing(0, Granularity.SECONDS);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue