diff --git a/ganttzk/src/main/java/org/zkoss/ganttz/util/ComponentsFinder.java b/ganttzk/src/main/java/org/zkoss/ganttz/util/ComponentsFinder.java index 852d8bd5c..056a13ace 100644 --- a/ganttzk/src/main/java/org/zkoss/ganttz/util/ComponentsFinder.java +++ b/ganttzk/src/main/java/org/zkoss/ganttz/util/ComponentsFinder.java @@ -25,6 +25,9 @@ import java.util.ArrayList; import java.util.List; import org.zkoss.zk.ui.Component; +import org.zkoss.zul.Grid; +import org.zkoss.zul.Row; +import org.zkoss.zul.api.Rows; /** * Utility methods to find components @@ -56,4 +59,18 @@ public class ComponentsFinder { return null; } + public static Row findRowByValue(Grid grid, Object needle) { + Rows rows = grid.getRows(); + for (Object each : rows.getChildren()) { + if (each instanceof Row) { + Row row = (Row) each; + Object value = row.getValue(); + if (needle.equals(value)) { + return row; + } + } + } + return null; + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java index a7a38f06f..ba470e723 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/exceptions/ValidationException.java @@ -69,6 +69,10 @@ public class ValidationException extends RuntimeException { return invalidValues.clone(); } + public InvalidValue getInvalidValue() { + return (invalidValues.length > 0) ? invalidValues.clone()[0] : null; + } + public ValidationException(InvalidValue invalidValue) { super(getValidationErrorSummary(invalidValue)); storeInvalidValues(toArray(invalidValue)); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/CostCategory.java b/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/CostCategory.java index e39d6ad33..3089e1c52 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/CostCategory.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/costcategories/entities/CostCategory.java @@ -21,6 +21,8 @@ package org.navalplanner.business.costcategories.entities; +import static org.navalplanner.business.i18n.I18nHelper._; + import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -29,6 +31,7 @@ import java.util.Set; import org.apache.commons.lang.StringUtils; import org.hibernate.validator.AssertFalse; import org.hibernate.validator.AssertTrue; +import org.hibernate.validator.InvalidValue; import org.hibernate.validator.NotEmpty; import org.hibernate.validator.NotNull; import org.hibernate.validator.Valid; @@ -37,6 +40,7 @@ import org.navalplanner.business.common.IntegrationEntity; import org.navalplanner.business.common.Registry; import org.navalplanner.business.common.entities.EntitySequence; import org.navalplanner.business.common.exceptions.InstanceNotFoundException; +import org.navalplanner.business.common.exceptions.ValidationException; import org.navalplanner.business.costcategories.daos.ICostCategoryDAO; /** @@ -243,4 +247,50 @@ public class CostCategory extends IntegrationEntity { public Integer getLastHourCostSequenceCode() { return lastHourCostSequenceCode; } -} + + public static void checkOverlapping( + List costCategoryAssignments) { + + for (int i = 0; i < costCategoryAssignments.size(); i++) { + LocalDate initDate = costCategoryAssignments.get(i).getInitDate(); + LocalDate endDate = costCategoryAssignments.get(i).getEndDate(); + for (int j = i + 1; j < costCategoryAssignments.size(); j++) { + ResourcesCostCategoryAssignment costCategory = costCategoryAssignments + .get(j); + if (endDate == null && costCategory.getEndDate() == null) { + throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory)); + } else if ((endDate == null && costCategory.getEndDate() + .compareTo(initDate) >= 0) + || (costCategory.getEndDate() == null && costCategory + .getInitDate().compareTo(endDate) <= 0)) { + throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory)); + } else if ((endDate != null && costCategory.getEndDate() != null) + && ((costCategory.getEndDate().compareTo(initDate) >= 0 && // (1) + // listElement.getEndDate() + // inside + // [initDate, + // endDate] + costCategory.getEndDate().compareTo(endDate) <= 0) + || (costCategory.getInitDate().compareTo( + initDate) >= 0 && // (2) + // listElement.getInitDate() + // inside [initDate, + // endDate] + costCategory.getInitDate().compareTo(endDate) <= 0) || (costCategory + .getInitDate().compareTo(initDate) <= 0 && // (3) + // [listElement.getInitDate(), + // listElement.getEndDate()] + costCategory.getEndDate().compareTo(endDate) >= 0))) { // contains + // [initDate, + // endDate] + throw new ValidationException(invalidValue(_("Some cost category assignments overlap in time"), costCategory)); + } + } + } + } + + private static InvalidValue invalidValue(String message, ResourcesCostCategoryAssignment each) { + return new InvalidValue(message, null, "", each, null); + } + +} \ No newline at end of file diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java index d01c30ce0..b6ad16fa7 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java @@ -52,6 +52,7 @@ import org.navalplanner.business.common.Registry; import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.common.exceptions.MultipleInstancesException; import org.navalplanner.business.common.exceptions.ValidationException; +import org.navalplanner.business.costcategories.entities.CostCategory; import org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment; import org.navalplanner.business.planner.entities.AvailabilityCalculator; import org.navalplanner.business.planner.entities.DayAssignment; @@ -1079,14 +1080,11 @@ public abstract class Resource extends IntegrationEntity { * Check if time intervals in cost assignments are correct in isolation. * If not, it does not make sense to check assignment overlapping. */ - for (ResourcesCostCategoryAssignment i : - getResourcesCostCategoryAssignments()) { - - if (!(i.isInitDateSpecified() && - i.checkConstraintPositiveTimeInterval())) { + for (ResourcesCostCategoryAssignment each : getResourcesCostCategoryAssignments()) { + if (!(each.isInitDateSpecified() && each + .checkConstraintPositiveTimeInterval())) { return false; } - } /* @@ -1095,28 +1093,11 @@ public abstract class Resource extends IntegrationEntity { List assignmentsList = new ArrayList(); assignmentsList.addAll(getResourcesCostCategoryAssignments()); - for(int i=0; i=0) || - (listElement.getEndDate() == null && listElement.getInitDate().compareTo(endDate)<=0)) { - return true; - } - else if((endDate != null && listElement.getEndDate() != null) && - ((listElement.getEndDate().compareTo(initDate)>=0 && // (1) listElement.getEndDate() inside [initDate, endDate] - listElement.getEndDate().compareTo(endDate)<=0) || - (listElement.getInitDate().compareTo(initDate)>=0 && // (2) listElement.getInitDate() inside [initDate, endDate] - listElement.getInitDate().compareTo(endDate)<=0) || - (listElement.getInitDate().compareTo(initDate)<=0 && // (3) [listElement.getInitDate(), listElement.getEndDate()] - listElement.getEndDate().compareTo(endDate)>=0))) { // contains [initDate, endDate] - return true; - } - } + + try { + CostCategory.checkOverlapping(assignmentsList); + } catch (ValidationException e) { + return true; } return false; diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/costcategories/ResourcesCostCategoryAssignmentController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/costcategories/ResourcesCostCategoryAssignmentController.java index 0df89f392..3cd8e31fa 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/costcategories/ResourcesCostCategoryAssignmentController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/costcategories/ResourcesCostCategoryAssignmentController.java @@ -27,7 +27,9 @@ import java.util.Date; import java.util.List; import org.apache.commons.logging.LogFactory; +import org.hibernate.validator.InvalidValue; import org.joda.time.LocalDate; +import org.navalplanner.business.common.exceptions.ValidationException; import org.navalplanner.business.costcategories.entities.CostCategory; import org.navalplanner.business.costcategories.entities.ResourcesCostCategoryAssignment; import org.navalplanner.business.resources.entities.Resource; @@ -38,7 +40,9 @@ import org.navalplanner.web.common.MessagesForUser; import org.navalplanner.web.common.Util; import org.navalplanner.web.common.components.Autocomplete; import org.navalplanner.web.workreports.WorkReportCRUDController; +import org.zkoss.ganttz.util.ComponentsFinder; import org.zkoss.zk.ui.Component; +import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zk.ui.event.Events; @@ -318,4 +322,25 @@ public class ResourcesCostCategoryAssignmentController extends GenericForwardCom public void validateConstraints() { ConstraintChecker.isValid(self); } + + /** + * Check there are not category assignment overlaps + * + * @return + */ + public boolean validate() { + List costCategoryAssignments = resourcesCostCategoryAssignmentModel + .getCostCategoryAssignments(); + try { + CostCategory.checkOverlapping(costCategoryAssignments); + } catch (ValidationException e) { + InvalidValue invalidValue = e.getInvalidValue(); + Component comp = ComponentsFinder.findRowByValue( + listResourcesCostCategoryAssignments, + invalidValue.getValue()); + throw new WrongValueException(comp, invalidValue.getMessage()); + } + return true; + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java index b67cee425..a1b0b53d1 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/resources/worker/WorkerCRUDController.java @@ -196,11 +196,19 @@ public class WorkerCRUDController extends GenericForwardComposer implements public boolean save() { validateConstraints(); + + // Validate 'Cost category assignment' tab is correct + if (resourcesCostCategoryAssignmentController != null) { + if (!resourcesCostCategoryAssignmentController.validate()) { + return false; + } + } + try { if (baseCalendarEditionController != null) { baseCalendarEditionController.save(); } - if(criterionsController != null){ + if (criterionsController != null){ if(!criterionsController.validate()){ return false; }