diff --git a/CHANGELOG.adoc b/CHANGELOG.adoc index d8a83e9..939df00 100644 --- a/CHANGELOG.adoc +++ b/CHANGELOG.adoc @@ -18,6 +18,7 @@ - https://github.com/ObeoNetwork/pepper/issues/18[#18] Enhance the ergonomy of contextual menu in Gantt - https://github.com/ObeoNetwork/pepper/issues/49[#49] Rework the detail views of Task and Workpackage - https://github.com/ObeoNetwork/pepper/issues/55[#55] Link detail view updates with Gantt view +- https://github.com/ObeoNetwork/pepper/issues/42[#42] Change behavior for start and end dates of a work package === Bug fixes diff --git a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/WorkpackageImpl.java b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/WorkpackageImpl.java index 0692554..d432fc6 100644 --- a/backend/pepper-mm/src/main/java/pepper/peppermm/impl/WorkpackageImpl.java +++ b/backend/pepper-mm/src/main/java/pepper/peppermm/impl/WorkpackageImpl.java @@ -12,8 +12,10 @@ ******************************************************************************/ package pepper.peppermm.impl; +import java.time.Instant; import java.time.LocalDate; +import java.time.ZoneId; import java.time.temporal.ChronoUnit; import java.util.Collection; @@ -367,13 +369,45 @@ public void setDescription(String newDescription) { /** * * - * @generated + * @generated NOT */ @Override public LocalDate getStartDate() { + if (ownedTasks != null && !ownedTasks.isEmpty()) { + Instant oldestInstant = null; + for (Task task : ownedTasks) { + Instant newOldestInstant = getOldestInstant(task, null); + if (oldestInstant == null || (newOldestInstant != null && newOldestInstant.isBefore(oldestInstant))) { + oldestInstant = newOldestInstant; + } + } + if (oldestInstant != null) { + return LocalDate.ofInstant(oldestInstant, ZoneId.systemDefault()); + } + } return startDate; } + /** + * + * + * @generated NOT + */ + private Instant getOldestInstant(Task task, Instant oldestInstant) { + Instant startTime = task.getStartTime(); + + if (startTime != null && (oldestInstant == null || startTime.isBefore(oldestInstant))) { + oldestInstant = startTime; + } + + if (task.getSubTasks() != null) { + for (Task subTask : task.getSubTasks()) { + oldestInstant = getOldestInstant(subTask, oldestInstant); + } + } + return oldestInstant; + } + /** * If the workpackage's {@code startDate} is constrained by {@code START_END}, it is not changed * @@ -406,13 +440,45 @@ public void setStartDate(LocalDate newStartDate) { /** * * - * @generated + * @generated NOT */ @Override public LocalDate getEndDate() { + if (ownedTasks != null && !ownedTasks.isEmpty()) { + Instant latestInstant = null; + for (Task task : ownedTasks) { + Instant newLattestInstant = getLatestInstant(task, null); + if (latestInstant == null || (newLattestInstant != null && newLattestInstant.isAfter(latestInstant))) { + latestInstant = newLattestInstant; + } + } + if (latestInstant != null) { + return LocalDate.ofInstant(latestInstant, ZoneId.systemDefault()); + } + } return endDate; } + /** + * + * + * @generated NOT + */ + private Instant getLatestInstant(Task task, Instant latestInstant) { + Instant endTime = task.getEndTime(); + + if (endTime != null && (latestInstant == null || endTime.isAfter(latestInstant))) { + latestInstant = endTime; + } + + if (task.getSubTasks() != null) { + for (Task subTask : task.getSubTasks()) { + latestInstant = getLatestInstant(subTask, latestInstant); + } + } + return latestInstant; + } + /** * If the workpackage's {@code endDate} is constrained by {@code START_END}, it is not changed * diff --git a/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java b/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java index 5548028..f97be65 100644 --- a/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java +++ b/backend/pepper-starter/src/main/java/pepper/starter/services/WorkpackagePropertiesConfigurer.java @@ -290,7 +290,10 @@ private TextfieldDescription getDurationWidget() { String id = "workpackage.duration"; return TextfieldDescription.newTextfieldDescription(id) .isReadOnlyProvider(vm -> vm.get(VariableManager.SELF, Workpackage.class) - .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.START_END || isDateOptionForced(workpackage)) + .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.START_END + || isDateOptionForced(workpackage) + || !workpackage.getOwnedTasks().isEmpty() + ) .orElse(true)) .idProvider(variableManager -> id) .targetObjectIdProvider(this.propertiesConfigurerService.getSemanticTargetIdProvider()) @@ -357,36 +360,6 @@ private ReferenceWidgetDescription getDependenciesWidget() { .build(); } - private Optional getItem(VariableManager variableManager) { - return variableManager.get(ReferenceWidgetComponent.ITEM_VARIABLE, Object.class); - } - - private List getReferenceValue(VariableManager variableManager, Object feature) { - List value = List.of(); - EStructuralFeature.Setting setting = this.resolveSetting(variableManager, feature); - if (setting != null) { - var rawValue = setting.get(true); - if (setting.getEStructuralFeature().isMany()) { - value = (List) rawValue; - } else if (rawValue != null) { - value = List.of(rawValue); - } else { - value = List.of(); - } - } - return value; - } - - private EStructuralFeature.Setting resolveSetting(VariableManager variableManager, Object feature) { - EObject referenceOwner = variableManager.get(VariableManager.SELF, EObject.class).orElse(null); - if (referenceOwner != null && feature instanceof EReference reference) { - return ((InternalEObject) referenceOwner).eSetting(reference); - } else { - return null; - } - } - - private DateTimeDescription getStartDateWidget() { Function valueProvider = variableManager -> variableManager.get(VariableManager.SELF, Workpackage.class) .map(workpackage -> { @@ -421,7 +394,11 @@ private DateTimeDescription getStartDateWidget() { String id = "workpackage.startTime"; return DateTimeDescription.newDateTimeDescription(id) .isReadOnlyProvider(vm -> vm.get(VariableManager.SELF, Workpackage.class) - .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.END_DURATION || isDateOptionForced(workpackage) || isPointed(workpackage, StartOrEnd.START)) + .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.END_DURATION + || isDateOptionForced(workpackage) + || isPointed(workpackage, StartOrEnd.START) + || !workpackage.getOwnedTasks().isEmpty() + ) .orElse(true)) .idProvider(variableManager -> id) .targetObjectIdProvider(this.propertiesConfigurerService.getSemanticTargetIdProvider()) @@ -469,7 +446,11 @@ private DateTimeDescription getEndDateWidget() { String id = "workpackage.endTime"; return DateTimeDescription.newDateTimeDescription(id) .isReadOnlyProvider(vm -> vm.get(VariableManager.SELF, Workpackage.class) - .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.START_DURATION || isDateOptionForced(workpackage) || isPointed(workpackage, StartOrEnd.END)) + .map(workpackage -> workpackage.getCalculationOption() == TaskTimeBoundariesConstraint.START_DURATION + || isDateOptionForced(workpackage) + || isPointed(workpackage, StartOrEnd.END) + || !workpackage.getOwnedTasks().isEmpty() + ) .orElse(true)) .idProvider(variableManager -> id) .targetObjectIdProvider(this.propertiesConfigurerService.getSemanticTargetIdProvider()) @@ -497,6 +478,35 @@ private Boolean isPointed(Workpackage workpackage, StartOrEnd startOrEnd) { return false; } + private Optional getItem(VariableManager variableManager) { + return variableManager.get(ReferenceWidgetComponent.ITEM_VARIABLE, Object.class); + } + + private List getReferenceValue(VariableManager variableManager, Object feature) { + List value = List.of(); + EStructuralFeature.Setting setting = this.resolveSetting(variableManager, feature); + if (setting != null) { + var rawValue = setting.get(true); + if (setting.getEStructuralFeature().isMany()) { + value = (List) rawValue; + } else if (rawValue != null) { + value = List.of(rawValue); + } else { + value = List.of(); + } + } + return value; + } + + private EStructuralFeature.Setting resolveSetting(VariableManager variableManager, Object feature) { + EObject referenceOwner = variableManager.get(VariableManager.SELF, EObject.class).orElse(null); + if (referenceOwner != null && feature instanceof EReference reference) { + return ((InternalEObject) referenceOwner).eSetting(reference); + } else { + return null; + } + } + private Function> getPersonsProvider() { return variableManager -> variableManager.get(VariableManager.SELF, EObject.class) .map(EObject::eResource)