diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/Flagged.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/Flagged.java
new file mode 100644
index 000000000..91c5c2d5a
--- /dev/null
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/Flagged.java
@@ -0,0 +1,92 @@
+/*
+ * This file is part of NavalPlan
+ *
+ * Copyright (C) 2011 Igalia, S.L.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.navalplanner.business.common;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Wraps a value with several arbitrary flags.
+ *
+ * @author Oscar Gonzalez Fernandez
+ *
+ * @param
+ * the value that can have flags associated with it
+ * @param
+ * the type of the flags
+ */
+public class Flagged {
+
+ public static Flagged justValue(T value) {
+ return new Flagged(value, new HashSet());
+ }
+
+ public static Flagged withFlags(T value, F... flags) {
+ return new Flagged(value, new HashSet(Arrays.asList(flags)));
+ }
+
+ private final T value;
+
+ private final Set flags;
+
+ private Flagged(T value, Set flags) {
+ this.value = value;
+ this.flags = Collections.unmodifiableSet(flags);
+ }
+
+ public Flagged withFlag(F flag) {
+ Set newFlags = new HashSet(flags);
+ newFlags.add(flag);
+ return new Flagged(value, newFlags);
+ }
+
+ public Flagged withoutFlag(F flag) {
+ Set newFlags = new HashSet(flags);
+ newFlags.remove(flag);
+ return new Flagged(value, newFlags);
+ }
+
+ public T getValue() {
+ return value;
+ }
+
+ public boolean isFlagged() {
+ return !this.flags.isEmpty();
+ }
+
+ public Set extends F> getFlags() {
+ return this.flags;
+ }
+
+ public boolean isFlaggedWith(F flag){
+ return this.flags.contains(flag);
+ }
+
+ public boolean isFlaggedWithSomeOf(F... flags) {
+ for (F each : flags) {
+ if (this.isFlaggedWith(each)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/allocationalgorithms/AllocationModification.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/allocationalgorithms/AllocationModification.java
index f79dbaec3..20c7aa2ff 100644
--- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/allocationalgorithms/AllocationModification.java
+++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/allocationalgorithms/AllocationModification.java
@@ -34,6 +34,16 @@ import org.navalplanner.business.resources.entities.Resource;
*/
public abstract class AllocationModification {
+ public static boolean allFullfiled(
+ Collection extends AllocationModification> modificationsDone) {
+ for (AllocationModification each : modificationsDone) {
+ if (!each.satisfiesModificationRequested()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static List> getBeingModified(
Collection extends AllocationModification> allocationModifications) {
List> result = new ArrayList>();
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/AllocationRowsHandler.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/AllocationRowsHandler.java
index bc99c0ce2..92d857dc2 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/AllocationRowsHandler.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/AllocationRowsHandler.java
@@ -29,6 +29,7 @@ import java.util.Set;
import org.joda.time.LocalDate;
import org.navalplanner.business.calendars.entities.ThereAreHoursOnWorkHoursCalculator.CapacityResult;
+import org.navalplanner.business.common.Flagged;
import org.navalplanner.business.orders.entities.HoursGroup;
import org.navalplanner.business.planner.entities.CalculatedValue;
import org.navalplanner.business.planner.entities.DerivedAllocationGenerator.IWorkerFinder;
@@ -229,7 +230,11 @@ public class AllocationRowsHandler {
return result;
}
- public AllocationResult doAllocation() {
+ public enum Warnings {
+ SOME_GOALS_NOT_FULFILLED;
+ }
+
+ public Flagged doAllocation() {
checkInvalidValues();
if (!currentRows.isEmpty()) {
List extends AllocationModification> modificationsDone;
@@ -238,10 +243,20 @@ public class AllocationRowsHandler {
AllocationRow.loadDataFromLast(currentRows, modificationsDone);
createDerived();
+ AllocationResult result = createResult();
+ if (AllocationModification.allFullfiled(modificationsDone)) {
+ return Flagged.justValue(result);
+ } else {
+ return Flagged.withFlags(result,
+ Warnings.SOME_GOALS_NOT_FULFILLED);
+ }
}
- AllocationResult result = AllocationResult.create(task,
+ return Flagged.justValue(createResult());
+ }
+
+ private AllocationResult createResult() {
+ return AllocationResult.create(task,
calculatedValue, currentRows, getWorkableDaysIfApplyable());
- return result;
}
private List extends AllocationModification> doSuitableAllocation() {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/FormBinder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/FormBinder.java
index 4c7281596..ad9f44e1a 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/FormBinder.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/FormBinder.java
@@ -34,6 +34,7 @@ import org.apache.commons.lang.Validate;
import org.joda.time.LocalDate;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
+import org.navalplanner.business.common.Flagged;
import org.navalplanner.business.common.ProportionalDistributor;
import org.navalplanner.business.planner.entities.AggregateOfResourceAllocations;
import org.navalplanner.business.planner.entities.CalculatedValue;
@@ -48,6 +49,7 @@ import org.navalplanner.web.common.Level;
import org.navalplanner.web.common.Util;
import org.navalplanner.web.common.components.NewAllocationSelectorCombo;
import org.navalplanner.web.common.components.ResourceAllocationBehaviour;
+import org.navalplanner.web.planner.allocation.AllocationRowsHandler.Warnings;
import org.navalplanner.web.planner.allocation.IResourceAllocationModel.IResourceAllocationContext;
import org.navalplanner.web.planner.taskedition.TaskPropertiesController;
import org.zkoss.util.Locales;
@@ -486,14 +488,35 @@ public class FormBinder {
}
public void doApply() {
- lastAllocation = resourceAllocationModel
+ AllocationResult allocationResult = resourceAllocationModel
.onAllocationContext(new IResourceAllocationContext() {
@Override
public AllocationResult doInsideTransaction() {
- return allocationRowsHandler.doAllocation();
+ return allocationRowsHandler.doAllocation().getValue();
}
});
+ allocationProduced(allocationResult);
+ }
+
+ /**
+ *
+ * @return true if and only if operation completed and must
+ * exit the edition form
+ */
+ public boolean accept() {
+ Flagged result = resourceAllocationModel
+ .accept();
+
+ // result can be null when editing milestones
+ if (result != null && result.isFlagged()) {
+ allocationProduced(result.getValue());
+ }
+ return result == null || !result.isFlagged();
+ }
+
+ private void allocationProduced(AllocationResult allocationResult) {
+ lastAllocation = allocationResult;
aggregate = lastAllocation.getAggregate();
allResourcesPerDayVisibilityRule();
sumResourcesPerDayFromRowsAndAssignToAllResourcesPerDay();
@@ -861,5 +884,4 @@ public class FormBinder {
this.behaviour = behaviour;
}
-
}
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/IResourceAllocationModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/IResourceAllocationModel.java
index ef90b7405..8ad6e27f5 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/IResourceAllocationModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/IResourceAllocationModel.java
@@ -24,10 +24,12 @@ package org.navalplanner.web.planner.allocation;
import java.util.Date;
import java.util.List;
+import org.navalplanner.business.common.Flagged;
import org.navalplanner.business.common.ProportionalDistributor;
import org.navalplanner.business.orders.entities.AggregatedHoursGroup;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.planner.entities.TaskElement;
+import org.navalplanner.web.planner.allocation.AllocationRowsHandler.Warnings;
import org.navalplanner.web.planner.order.PlanningState;
import org.zkoss.ganttz.extensions.IContextWithPlannerTask;
@@ -50,8 +52,10 @@ public interface IResourceAllocationModel extends INewAllocationsAdder {
/**
* Save task
+ *
+ * @return
*/
- void accept();
+ Flagged accept();
/**
* Starts the use case
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationController.java
index 48c644446..85b2af27e 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationController.java
@@ -597,9 +597,17 @@ public class ResourceAllocationController extends GenericForwardComposer {
allocationsGrid.setModel(new SimpleListModel(Collections.emptyList()));
}
- public void accept() {
- resourceAllocationModel.accept();
- clear();
+ /**
+ *
+ * @return true if it must exist false if exit
+ * must be prevented
+ */
+ public boolean accept() {
+ boolean mustExit = formBinder.accept();
+ if (mustExit) {
+ clear();
+ }
+ return mustExit;
}
private class ResourceAllocationRenderer implements RowRenderer {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationModel.java
index debaa778d..18cb1973e 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationModel.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/allocation/ResourceAllocationModel.java
@@ -28,6 +28,7 @@ import java.util.List;
import java.util.Set;
import org.hibernate.Hibernate;
+import org.navalplanner.business.common.Flagged;
import org.navalplanner.business.common.IAdHocTransactionService;
import org.navalplanner.business.common.IOnTransaction;
import org.navalplanner.business.common.ProportionalDistributor;
@@ -39,11 +40,11 @@ import org.navalplanner.business.planner.daos.ITaskElementDAO;
import org.navalplanner.business.planner.daos.ITaskSourceDAO;
import org.navalplanner.business.planner.entities.DayAssignment;
import org.navalplanner.business.planner.entities.DerivedAllocation;
+import org.navalplanner.business.planner.entities.DerivedAllocationGenerator.IWorkerFinder;
import org.navalplanner.business.planner.entities.GenericResourceAllocation;
import org.navalplanner.business.planner.entities.ResourceAllocation;
import org.navalplanner.business.planner.entities.Task;
import org.navalplanner.business.planner.entities.TaskElement;
-import org.navalplanner.business.planner.entities.DerivedAllocationGenerator.IWorkerFinder;
import org.navalplanner.business.resources.daos.ICriterionDAO;
import org.navalplanner.business.resources.daos.IResourceDAO;
import org.navalplanner.business.resources.daos.IResourcesSearcher;
@@ -55,6 +56,7 @@ import org.navalplanner.business.resources.entities.MachineWorkersConfigurationU
import org.navalplanner.business.resources.entities.Resource;
import org.navalplanner.business.resources.entities.ResourceEnum;
import org.navalplanner.business.resources.entities.Worker;
+import org.navalplanner.web.planner.allocation.AllocationRowsHandler.Warnings;
import org.navalplanner.web.planner.order.PlanningState;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
@@ -169,42 +171,52 @@ public class ResourceAllocationModel implements IResourceAllocationModel {
}
@Override
- public void accept() {
+ public Flagged accept() {
if (context != null) {
- applyAllocationWithDateChangesNotification(new IOnTransaction() {
+ return applyDateChangesNotificationIfNoFlags(new IOnTransaction>() {
@Override
- public Void execute() {
+ public Flagged execute() {
stepsBeforeDoingAllocation();
- allocationRowsHandler.doAllocation().applyTo(
- planningState.getCurrentScenario(), task);
- return null;
+ Flagged allocationResult = allocationRowsHandler
+ .doAllocation();
+ if (!allocationResult.isFlagged()) {
+ allocationResult.getValue().applyTo(
+ planningState.getCurrentScenario(), task);
+ }
+ return allocationResult;
}
});
}
+ return null;
}
@Override
public void accept(final AllocationResult modifiedAllocationResult) {
if (context != null) {
- applyAllocationWithDateChangesNotification(new IOnTransaction() {
+ applyDateChangesNotificationIfNoFlags(new IOnTransaction>() {
@Override
- public Void execute() {
+ public Flagged execute() {
stepsBeforeDoingAllocation();
modifiedAllocationResult.applyTo(planningState
.getCurrentScenario(), task);
- return null;
+
+ return Flagged.justValue(null);
}
});
}
}
- private void applyAllocationWithDateChangesNotification(
- IOnTransaction> allocationDoer) {
+ private > T applyDateChangesNotificationIfNoFlags(
+ IOnTransaction allocationDoer) {
org.zkoss.ganttz.data.Task ganttTask = context.getTask();
GanttDate previousStartDate = ganttTask.getBeginDate();
GanttDate previousEnd = ganttTask.getEndDate();
- transactionService.runOnReadOnlyTransaction(allocationDoer);
- ganttTask.fireChangesForPreviousValues(previousStartDate, previousEnd);
+ T result = transactionService.runOnReadOnlyTransaction(allocationDoer);
+ if (!result.isFlagged()) {
+ ganttTask.fireChangesForPreviousValues(previousStartDate,
+ previousEnd);
+ }
+ return result;
}
private void stepsBeforeDoingAllocation() {
diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/taskedition/EditTaskController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/taskedition/EditTaskController.java
index 73c7b62c5..8caf496cf 100644
--- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/taskedition/EditTaskController.java
+++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/taskedition/EditTaskController.java
@@ -282,7 +282,10 @@ public class EditTaskController extends GenericForwardComposer {
ResourceAllocationTypeEnum currentState = taskPropertiesController.getCurrentState();
if (ResourceAllocationTypeEnum.NON_LIMITING_RESOURCES.equals(currentState)) {
editTaskTabbox.setSelectedPanelApi(resourceAllocationTabpanel);
- resourceAllocationController.accept();
+ boolean mustNotExit = !resourceAllocationController.accept();
+ if (mustNotExit) {
+ return;
+ }
} else if (ResourceAllocationTypeEnum.SUBCONTRACT.equals(currentState)) {
editTaskTabbox.setSelectedPanelApi(subcontractTabpanel);
subcontractController.accept();