Respect dependency constraints for manual allocation
Manual allocation, either appropriative and non-appropriative, didn't respect dependency constraints. Now manual allocation respects dependencies in the same manner as automatic allocation FEA: ItEr65OTS04CorreccionsRecursosLimitantes
This commit is contained in:
parent
c3f78fcc8f
commit
a2f359013e
4 changed files with 131 additions and 51 deletions
|
|
@ -25,6 +25,7 @@ import static org.navalplanner.business.workingday.EffortDuration.zero;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
|
@ -65,6 +66,16 @@ public class Gap implements Comparable<Gap> {
|
|||
return result;
|
||||
}
|
||||
|
||||
public static List<GapOnQueue> onQueue(
|
||||
LimitingResourceQueue queue, DateAndHour startTime,
|
||||
DateAndHour endTime) {
|
||||
|
||||
Gap gap = (endTime == null || endTime.compareTo(startTime) <= 0) ? Gap
|
||||
.untilEnd(queue.getResource(), startTime) : Gap.create(
|
||||
queue.getResource(), startTime, endTime);
|
||||
return GapOnQueue.onQueue(queue, Collections.singleton(gap));
|
||||
}
|
||||
|
||||
private final LimitingResourceQueue originQueue;
|
||||
|
||||
private final Gap gap;
|
||||
|
|
@ -93,7 +104,11 @@ public class Gap implements Comparable<Gap> {
|
|||
|
||||
public static Gap untilEnd(LimitingResourceQueueElement current,
|
||||
DateAndHour startInclusive) {
|
||||
return new Gap(current.getResource(), startInclusive, null);
|
||||
return untilEnd(current.getResource(), startInclusive);
|
||||
}
|
||||
|
||||
private static Gap untilEnd(Resource resource, DateAndHour startInclusive) {
|
||||
return new Gap(resource, startInclusive, null);
|
||||
}
|
||||
|
||||
private DateAndHour startTime;
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
package org.navalplanner.web.limitingresources;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.navalplanner.business.orders.entities.Order;
|
||||
import org.navalplanner.business.planner.entities.DayAssignment;
|
||||
|
|
@ -55,7 +56,7 @@ import org.zkoss.ganttz.util.Interval;
|
|||
*/
|
||||
public interface ILimitingResourceQueueModel {
|
||||
|
||||
boolean nonAppropriativeAllocation(
|
||||
List<LimitingResourceQueueElement> nonAppropriativeAllocation(
|
||||
LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time);
|
||||
|
||||
/**
|
||||
|
|
@ -127,7 +128,8 @@ public interface ILimitingResourceQueueModel {
|
|||
* @param queue
|
||||
* @param allocationTime
|
||||
*/
|
||||
void appropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue,
|
||||
Set<LimitingResourceQueueElement> appropriativeAllocation(
|
||||
LimitingResourceQueueElement element, LimitingResourceQueue queue,
|
||||
DateAndHour allocationTime);
|
||||
|
||||
void unschedule(LimitingResourceQueueElement element);
|
||||
|
|
|
|||
|
|
@ -415,6 +415,7 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
@Override
|
||||
public List<LimitingResourceQueueElement> assignLimitingResourceQueueElement(
|
||||
LimitingResourceQueueElement externalQueueElement) {
|
||||
|
||||
InsertionRequirements requirements = queuesState
|
||||
.getRequirementsFor(externalQueueElement);
|
||||
AllocationSpec allocationDone = insertAtGap(requirements);
|
||||
|
|
@ -612,19 +613,46 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
return Collections.singletonList(each);
|
||||
}
|
||||
|
||||
private void applyAllocation(AllocationSpec allocationStillNotDone) {
|
||||
private void applyAllocation(final AllocationSpec allocationStillNotDone) {
|
||||
applyAllocation(allocationStillNotDone, new IDayAssignmentBehaviour() {
|
||||
|
||||
@Override
|
||||
public void allocateDayAssigments() {
|
||||
ResourceAllocation<?> resourceAllocation = getResourceAllocation(allocationStillNotDone);
|
||||
Resource resource = getResource(allocationStillNotDone);
|
||||
|
||||
List<DayAssignment> assignments = allocationStillNotDone.getAssignmentsFor(
|
||||
resourceAllocation, resource);
|
||||
resourceAllocation.allocateLimitingDayAssignments(assignments);
|
||||
}
|
||||
|
||||
private ResourceAllocation<?> getResourceAllocation(AllocationSpec allocation) {
|
||||
return allocation.getElement().getResourceAllocation();
|
||||
}
|
||||
|
||||
private Resource getResource(AllocationSpec allocation) {
|
||||
return allocation.getQueue().getResource();
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
private void applyAllocation(AllocationSpec allocationStillNotDone,
|
||||
IDayAssignmentBehaviour allocationBehaviour) {
|
||||
|
||||
// Do day allocation
|
||||
allocationBehaviour.allocateDayAssigments();
|
||||
|
||||
LimitingResourceQueueElement element = allocationStillNotDone
|
||||
.getElement();
|
||||
.getElement();
|
||||
LimitingResourceQueue queue = allocationStillNotDone.getQueue();
|
||||
Resource resource = queue.getResource();
|
||||
ResourceAllocation<?> resourceAllocation = element.getResourceAllocation();
|
||||
List<DayAssignment> assignments = allocationStillNotDone
|
||||
.getAssignmentsFor(resourceAllocation, resource);
|
||||
resourceAllocation
|
||||
.allocateLimitingDayAssignments(assignments);
|
||||
|
||||
// Update start and end time of task
|
||||
updateStartAndEndTimes(element, allocationStillNotDone
|
||||
.getStartInclusive(), allocationStillNotDone
|
||||
.getEndExclusive());
|
||||
|
||||
// Add to queue and mark as modified
|
||||
addLimitingResourceQueueElementIfNeeded(queue, element);
|
||||
markAsModified(element);
|
||||
}
|
||||
|
|
@ -635,43 +663,64 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
.getEarliestEndDateBecauseOfGantt()));
|
||||
}
|
||||
|
||||
private boolean assignLimitingResourceQueueElementToQueueAt(
|
||||
LimitingResourceQueueElement element, LimitingResourceQueue queue,
|
||||
DateAndHour startTime, DateAndHour endsAfter) {
|
||||
private List<LimitingResourceQueueElement> assignLimitingResourceQueueElementToQueueAt(
|
||||
final LimitingResourceQueueElement element,
|
||||
final LimitingResourceQueue queue, final DateAndHour startTime,
|
||||
final DateAndHour endsAfter) {
|
||||
|
||||
// Allocate day assignments and adjust start and end times for element
|
||||
List<DayAssignment> dayAssignments = LimitingResourceAllocator
|
||||
.generateDayAssignments(element.getResourceAllocation(), queue
|
||||
.getResource(), startTime, endsAfter);
|
||||
element.getResourceAllocation().allocateLimitingDayAssignments(
|
||||
dayAssignments);
|
||||
|
||||
DateAndHour endTime = endFor(dayAssignments);
|
||||
// the assignments can be generated after the required start
|
||||
startTime = DateAndHour.max(startTime, startFor(dayAssignments));
|
||||
if (sameDay(startTime, endTime)) {
|
||||
endTime = new DateAndHour(endTime.getDate(), startTime.getHour() + endTime.getHour());
|
||||
// Check if allocation is possible
|
||||
InsertionRequirements requirements = queuesState
|
||||
.getRequirementsFor(element);
|
||||
List<GapOnQueue> gapOnQueue = GapOnQueue.onQueue(queue, startTime,
|
||||
endsAfter);
|
||||
AllocationSpec allocation = requirements.guessValidity(gapOnQueue
|
||||
.iterator().next());
|
||||
if (!allocation.isValid()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
updateStartAndEndTimes(element, startTime, endTime);
|
||||
|
||||
// Add element to queue
|
||||
addLimitingResourceQueueElementIfNeeded(queue, element);
|
||||
markAsModified(element);
|
||||
return true;
|
||||
// Do allocation
|
||||
applyAllocation(allocation, new IDayAssignmentBehaviour() {
|
||||
|
||||
@Override
|
||||
public void allocateDayAssigments() {
|
||||
|
||||
List<DayAssignment> assignments = LimitingResourceAllocator
|
||||
.generateDayAssignments(
|
||||
element.getResourceAllocation(),
|
||||
queue.getResource(), startTime, endsAfter);
|
||||
element.getResourceAllocation().allocateLimitingDayAssignments(
|
||||
assignments);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
assert allocation.isValid();
|
||||
|
||||
// Move other tasks to respect dependency constraints
|
||||
List<LimitingResourceQueueElement> result = new ArrayList<LimitingResourceQueueElement>();
|
||||
result.add(requirements.getElement());
|
||||
|
||||
List<LimitingResourceQueueElement> moved = shift(
|
||||
queuesState.getPotentiallyAffectedByInsertion(element),
|
||||
requirements.getElement(), allocation);
|
||||
|
||||
// Return all moved tasks (including the allocated one)
|
||||
result.addAll(moved);
|
||||
return result;
|
||||
}
|
||||
|
||||
private DateAndHour endFor(List<DayAssignment> dayAssignments) {
|
||||
DayAssignment last = dayAssignments.get(dayAssignments.size() - 1);
|
||||
return new DateAndHour(last.getDay(), 0);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* Describes how day assignments are going to be generated for an allocation
|
||||
*
|
||||
* @author Diego Pino García<dpino@igalia.com>
|
||||
*
|
||||
*/
|
||||
private interface IDayAssignmentBehaviour {
|
||||
|
||||
private DateAndHour startFor(List<DayAssignment> dayAssignments) {
|
||||
return new DateAndHour(dayAssignments
|
||||
.get(0).getDay(), 0);
|
||||
}
|
||||
void allocateDayAssigments();
|
||||
|
||||
private boolean sameDay(DateAndHour startTime, DateAndHour endTime) {
|
||||
return startTime.getDate().equals(endTime.getDate());
|
||||
}
|
||||
|
||||
private void markAsModified(LimitingResourceQueueElement element) {
|
||||
|
|
@ -890,7 +939,7 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean nonAppropriativeAllocation(
|
||||
public List<LimitingResourceQueueElement> nonAppropriativeAllocation(
|
||||
LimitingResourceQueueElement element,
|
||||
LimitingResourceQueue queue,
|
||||
DateAndHour startTime) {
|
||||
|
|
@ -918,9 +967,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
|
||||
|
||||
@Override
|
||||
public void appropriativeAllocation(LimitingResourceQueueElement _element, LimitingResourceQueue _queue,
|
||||
public Set<LimitingResourceQueueElement> appropriativeAllocation(LimitingResourceQueueElement _element, LimitingResourceQueue _queue,
|
||||
DateAndHour allocationTime) {
|
||||
|
||||
Set<LimitingResourceQueueElement> result = new HashSet<LimitingResourceQueueElement>();
|
||||
|
||||
LimitingResourceQueue queue = queuesState.getEquivalent(_queue);
|
||||
LimitingResourceQueueElement element = queuesState.getEquivalent(_element);
|
||||
|
||||
|
|
@ -938,8 +989,9 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
final LocalDate startDate = gap.getStartTime().getDate();
|
||||
|
||||
if (startDate.equals(allocationTime.getDate())) {
|
||||
assignLimitingResourceQueueElementToQueueAt(element, queue,
|
||||
allocationTime, getEndsAfterBecauseOfGantt(element));
|
||||
result.addAll(assignLimitingResourceQueueElementToQueueAt(
|
||||
element, queue, allocationTime,
|
||||
getEndsAfterBecauseOfGantt(element)));
|
||||
break;
|
||||
} else {
|
||||
LimitingResourceQueueElement elementAtTime = getFirstElementFrom(
|
||||
|
|
@ -954,10 +1006,11 @@ public class LimitingResourceQueueModel implements ILimitingResourceQueueModel {
|
|||
|
||||
for (LimitingResourceQueueElement each: unscheduledElements) {
|
||||
gap = LimitingResourceAllocator.getFirstValidGap(queue, each);
|
||||
assignLimitingResourceQueueElementToQueueAt(each, queue, gap
|
||||
.getStartTime(), getEndsAfterBecauseOfGantt(element));
|
||||
result.addAll(assignLimitingResourceQueueElementToQueueAt(each, queue, gap
|
||||
.getStartTime(), getEndsAfterBecauseOfGantt(element)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
|
|
|||
|
|
@ -22,10 +22,12 @@ package org.navalplanner.web.limitingresources;
|
|||
|
||||
import static org.navalplanner.web.I18nHelper._;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.joda.time.LocalDate;
|
||||
|
|
@ -278,15 +280,23 @@ public class ManualAllocationController extends GenericForwardComposer {
|
|||
|
||||
private void nonAppropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time) {
|
||||
Validate.notNull(time);
|
||||
getLimitingResourceQueueModel()
|
||||
List<LimitingResourceQueueElement> inserted = getLimitingResourceQueueModel()
|
||||
.nonAppropriativeAllocation(element, queue, time);
|
||||
limitingResourcesPanel.appendQueueElementToQueue(element);
|
||||
refreshQueues(inserted);
|
||||
}
|
||||
|
||||
private void appropriativeAllocation(LimitingResourceQueueElement element, LimitingResourceQueue queue, DateAndHour time) {
|
||||
Validate.notNull(time);
|
||||
getLimitingResourceQueueModel().appropriativeAllocation(element, queue, time);
|
||||
limitingResourcesPanel.refreshQueue(queue);
|
||||
Set<LimitingResourceQueueElement> inserted = getLimitingResourceQueueModel()
|
||||
.appropriativeAllocation(element, queue, time);
|
||||
refreshQueues(inserted);
|
||||
}
|
||||
|
||||
private void refreshQueues(Collection<LimitingResourceQueueElement> movedElements) {
|
||||
for (LimitingResourceQueueElement each : movedElements) {
|
||||
limitingResourcesPanel.removeDependencyComponentsFor(each);
|
||||
limitingResourcesPanel.refreshQueue(each.getLimitingResourceQueue());
|
||||
}
|
||||
}
|
||||
|
||||
private DateAndHour getSelectedAllocationTime() {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue