/* * This file is part of LibrePlan * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia * Copyright (C) 2010-2012 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 <http://www.gnu.org/licenses/>. */ package org.libreplan.business.orders.entities; import static org.libreplan.business.i18n.I18nHelper._; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; import javax.validation.Valid; import javax.validation.constraints.AssertTrue; import org.joda.time.LocalDate; import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes; import org.libreplan.business.advance.entities.AdvanceAssignment; import org.libreplan.business.advance.entities.AdvanceMeasurement; import org.libreplan.business.advance.entities.AdvanceMeasurementComparator; import org.libreplan.business.advance.entities.AdvanceType; import org.libreplan.business.advance.entities.DirectAdvanceAssignment; import org.libreplan.business.advance.entities.IndirectAdvanceAssignment; import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException; import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException; import org.libreplan.business.labels.entities.Label; import org.libreplan.business.materials.entities.MaterialAssignment; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.TaskGroup; import org.libreplan.business.qualityforms.entities.TaskQualityForm; import org.libreplan.business.scenarios.entities.OrderVersion; import org.libreplan.business.templates.entities.OrderElementTemplate; import org.libreplan.business.templates.entities.OrderLineGroupTemplate; import org.libreplan.business.trees.ITreeParentNode; /** * Represents every container in the WBS view. A task of the WBS that has some children. * <br /> * The project itself is also an {@link OrderLineGroup}. * * @author Manuel Rego Casasnovas <rego@igalia.com> */ public class OrderLineGroup extends OrderElement implements ITreeParentNode<OrderElement> { private final class ChildrenManipulator extends TreeNodeOnListWithSchedulingState<OrderElement> { private ChildrenManipulator(List<OrderElement> children) { super(children); } @Override protected void setParentIfRequired(OrderElement newChild) { newChild.setParent(getThis()); } @Override protected void updateWithNewChild(SchedulingState newChildState) { getThis().getSchedulingState().add(newChildState); } @Override protected SchedulingState getSchedulingStateFrom(OrderElement node) { if ( !node.isSchedulingDataInitialized() ) { node.useSchedulingDataFor(getCurrentSchedulingData().getOriginOrderVersion()); } return node.getSchedulingState(); } @Override protected void onChildAddedAdditionalActions(OrderElement newChild) { updateCriterionRequirements(); newChild.updateLabels(); if ( !newChild.isNewObject() ) { getOrder().markAsNeededToRecalculateSumChargedEfforts(); getOrder().markAsNeededToRecalculateSumExpenses(); } } @Override protected void onChildRemovedAdditionalActions(OrderElement removedChild) { if ( removedChild.isScheduled() && getThis().isScheduled() ) { removeChildTask(removedChild); } updateCriterionRequirements(); if ( !removedChild.isNewObject() ) { getOrder().markAsNeededToRecalculateSumChargedEfforts(); getOrder().markAsNeededToRecalculateSumExpenses(); } } private void removeChildTask(OrderElement removedChild) { TaskSource taskSource = removedChild.getTaskSource(); TaskElement childTask = taskSource.getTask(); TaskGroup group = (TaskGroup) getThis().getTaskSource().getTask(); group.remove(childTask); childTask.detachDependencies(); } @Override public ITreeParentNode<OrderElement> getParent() { return getThis().getParent(); } @Override public ITreeParentNode<OrderElement> toContainer() { return OrderLineGroup.this.toContainer(); } @Override public OrderElement toLeaf() { return getThis().toLeaf(); } @Override public OrderLineGroup getThis() { return OrderLineGroup.this; } @Override public boolean isLeaf() { return false; } @Override public boolean isEmptyLeaf() { return false; } @Override public boolean isUpdatedFromTimesheets() { return getThis().isUpdatedFromTimesheets(); } @Override public boolean isJiraIssue() { return getThis().isJiraIssue(); } } public static OrderLineGroup create() { OrderLineGroup result = new OrderLineGroup(); result.setNewObject(true); return result; } public static OrderLineGroup createUnvalidated(String code) { return create(new OrderLineGroup(), code); } public void addChildrenAdvanceOrderLineGroup() { boolean spread = (getReportGlobalAdvanceAssignment() == null); IndirectAdvanceAssignment indirectAdvanceAssignment = IndirectAdvanceAssignment.create(spread); AdvanceType advanceType = PredefinedAdvancedTypes.CHILDREN.getType(); indirectAdvanceAssignment.setAdvanceType(advanceType); indirectAdvanceAssignment.setOrderElement(this); addIndirectAdvanceAssignment(indirectAdvanceAssignment); } public void removeChildrenAdvanceOrderLineGroup() { for (IndirectAdvanceAssignment advance : getIndirectAdvanceAssignments()) { if ( advance.getAdvanceType().getUnitName().equals(PredefinedAdvancedTypes.CHILDREN.getTypeName()) ) { indirectAdvanceAssignments.remove(advance); updateSpreadAdvance(); } } } @Override protected void updateSpreadAdvance() { if ( getReportGlobalAdvanceAssignment() == null ) { boolean condition; // Set CHILDREN type as spread if any String type = PredefinedAdvancedTypes.CHILDREN.getTypeName(); for (IndirectAdvanceAssignment each : indirectAdvanceAssignments) { condition = each.getAdvanceType() != null && each.getAdvanceType().getType() != null && each.getAdvanceType().getType().equals(type); if ( condition ) { each.setReportGlobalAdvance(true); return; } } // Otherwise, set first indirect advance assignment if ( !indirectAdvanceAssignments.isEmpty() ) { indirectAdvanceAssignments.iterator().next().setReportGlobalAdvance(true); return; } super.updateSpreadAdvance(); } } public boolean existChildrenAdvance() { return (getChildrenAdvance() != null); } public IndirectAdvanceAssignment getChildrenAdvance() { for (IndirectAdvanceAssignment advance : getIndirectAdvanceAssignments()) { if ( advance.getAdvanceType().getUnitName().equals(PredefinedAdvancedTypes.CHILDREN.getTypeName()) ) { return advance; } } return null; } private List<OrderElement> children = new ArrayList<>(); private Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = new HashSet<>(); /** * Constructor for hibernate. Do not use! */ public OrderLineGroup() { } @Override @Valid public List<OrderElement> getChildren() { return new ArrayList<>(children); } @Override public boolean isLeaf() { return false; } @Override public boolean isEmptyLeaf() { return false; } @Override public void remove(OrderElement child) { getManipulator().remove(child); removeIndirectAdvanceAssignments(child); } @Override public void replace(OrderElement oldOrderElement, OrderElement orderElement) { getManipulator().replace(oldOrderElement, orderElement); addIndirectAdvanceAssignments(orderElement); removeIndirectAdvanceAssignments(oldOrderElement); } @Override public void add(OrderElement orderElement) { getManipulator().add(orderElement); addIndirectAdvanceAssignments(orderElement); } private void addIndirectAdvanceAssignments(OrderElement orderElement) { orderElement.removeDirectAdvancesInList(getDirectAdvanceAssignmentsAndAllInAncest()); for (DirectAdvanceAssignment directAdvanceAssignment : orderElement.directAdvanceAssignments) { IndirectAdvanceAssignment indirectAdvanceAssignment = IndirectAdvanceAssignment.create(); indirectAdvanceAssignment.setAdvanceType(directAdvanceAssignment.getAdvanceType()); indirectAdvanceAssignment.setOrderElement(this); this.addIndirectAdvanceAssignment(indirectAdvanceAssignment); } if ( orderElement instanceof OrderLineGroup ) { for (IndirectAdvanceAssignment indirectAdvanceAssignment : orderElement.getIndirectAdvanceAssignments()) { this.addIndirectAdvanceAssignment(indirectAdvanceAssignment); } } if ( !indirectAdvanceAssignments.isEmpty() ) { addChildrenAdvanceOrderLineGroup(); } } private void removeIndirectAdvanceAssignments(OrderElement orderElement) { for (DirectAdvanceAssignment directAdvanceAssignment : orderElement.directAdvanceAssignments) { this.removeIndirectAdvanceAssignment(directAdvanceAssignment.getAdvanceType()); } if (orderElement instanceof OrderLineGroup) { for (IndirectAdvanceAssignment indirectAdvanceAssignment : orderElement.getIndirectAdvanceAssignments()) { this.removeIndirectAdvanceAssignment(indirectAdvanceAssignment.getAdvanceType()); } } if ( children.isEmpty() && (indirectAdvanceAssignments.size() == 1) && existChildrenAdvance() ) { removeChildrenAdvanceOrderLineGroup(); } } @Override public void up(OrderElement orderElement) { getManipulator().up(orderElement); } private ChildrenManipulator getManipulator() { return new ChildrenManipulator(children); } @Override public OrderLine toLeaf() { OrderLine result = OrderLine.create(); result.infoComponent = getInfoComponent().copy(); result.setCode(getCode()); setCode(""); result.setInitDate(getInitDate()); result.setDeadline(getDeadline()); result.setWorkHours(0); result.directAdvanceAssignments = copyDirectAdvanceAssignments(this, result); result.materialAssignments = copyMaterialAssignments(this, result); result.labels = copyLabels(this, result); result.taskQualityForms = copyTaskQualityForms(this, result); copyRequirementToOrderElement(result); result.initializeTemplate(this.getTemplate()); result.setExternalCode(getExternalCode()); return result; } private static Set<DirectAdvanceAssignment> copyDirectAdvanceAssignments(OrderElement origin, OrderElement destination) { Set<DirectAdvanceAssignment> result = new HashSet<>(); for (DirectAdvanceAssignment each : origin.directAdvanceAssignments) { result.add(DirectAdvanceAssignment.copy(each, destination)); } return result; } private static Set<MaterialAssignment> copyMaterialAssignments(OrderElement origin, OrderElement destination) { Set<MaterialAssignment> result = new HashSet<>(); for (MaterialAssignment each : origin.materialAssignments) { result.add(MaterialAssignment.copy(each, destination)); } return result; } private static Set<Label> copyLabels(OrderElement origin, OrderElement destination) { Set<Label> result = new HashSet<>(); for (Label each : origin.labels) { destination.addLabel(each); result.add(each); } return result; } private static Set<TaskQualityForm> copyTaskQualityForms(OrderElement origin, OrderElement destination) { Set<TaskQualityForm> result = new HashSet<>(); for (TaskQualityForm each : origin.taskQualityForms) { result.add(TaskQualityForm.copy(each, destination)); } return result; } @Override public OrderLineGroup toContainer() { return this; } @Override public void down(OrderElement orderElement) { getManipulator().down(orderElement); } @Override public void add(int position, OrderElement orderElement) { getManipulator().add(position, orderElement); addIndirectAdvanceAssignments(orderElement); } @Override public Integer getWorkHours() { int result = 0; for (OrderElement orderElement : getChildren()) { result += orderElement.getWorkHours(); } return result; } @Override public List<HoursGroup> getHoursGroups() { List<HoursGroup> hoursGroups = new ArrayList<>(); for (OrderElement orderElement : children) { hoursGroups.addAll(orderElement.getHoursGroups()); } return hoursGroups; } public BigDecimal getAdvancePercentage(AdvanceType advanceType, LocalDate date) { final DirectAdvanceAssignment directAdvanceAssignment = this.getAdvanceAssignmentByType(advanceType); if ( directAdvanceAssignment != null ) { return directAdvanceAssignment.getAdvancePercentage(date); } return null; } @Override public BigDecimal getAdvancePercentage(LocalDate date) { for (DirectAdvanceAssignment directAdvanceAssignment : directAdvanceAssignments) { if ( directAdvanceAssignment.getReportGlobalAdvance() ) { if ( date == null ) { return directAdvanceAssignment.getAdvancePercentage(); } return directAdvanceAssignment.getAdvancePercentage(date); } } for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) { if ( indirectAdvanceAssignment.getReportGlobalAdvance() ) { if ( indirectAdvanceAssignment.getAdvanceType().getUnitName().equals( PredefinedAdvancedTypes.CHILDREN.getTypeName()) ) { if ( date == null ) { return getAdvancePercentageChildren(); } return getAdvancePercentageChildren(date); } else { DirectAdvanceAssignment directAdvanceAssignment = calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment); if ( date == null ) { return directAdvanceAssignment.getAdvancePercentage(); } return directAdvanceAssignment.getAdvancePercentage(date); } } } return BigDecimal.ZERO; } @Override public BigDecimal getAdvancePercentageChildren() { return getAdvancePercentageChildren(null); } public BigDecimal getAdvancePercentageChildren(LocalDate date) { Integer hours = getWorkHours(); BigDecimal result = new BigDecimal(0); if ( hours > 0 ) { for (OrderElement orderElement : children) { BigDecimal childPercentage; if ( date == null ) { childPercentage = orderElement.getAdvancePercentage(); } else { childPercentage = orderElement.getAdvancePercentage(date); } Integer childHours = orderElement.getWorkHours(); result = result.add(childPercentage.multiply(new BigDecimal(childHours))); } result = result.divide(new BigDecimal(hours).setScale(2), 4, RoundingMode.DOWN); } return result; } @Override public DirectAdvanceAssignment calculateFakeDirectAdvanceAssignment( IndirectAdvanceAssignment indirectAdvanceAssignment) { boolean condition = indirectAdvanceAssignment.getAdvanceType().getUnitName() .equals(PredefinedAdvancedTypes.CHILDREN.getTypeName()); if ( condition ) { return calculateFakeDirectAdvanceAssignmentChildren(indirectAdvanceAssignment); } else { Set<DirectAdvanceAssignment> directAdvanceAssignments = getAllDirectAdvanceAssignments(indirectAdvanceAssignment.getAdvanceType()); return mergeAdvanceAssignments(new ArrayList<>(directAdvanceAssignments)); } } private DirectAdvanceAssignment calculateFakeDirectAdvanceAssignmentChildren( IndirectAdvanceAssignment indirectAdvanceAssignment) { DirectAdvanceAssignment newDirectAdvanceAssignment = DirectAdvanceAssignment.create(); newDirectAdvanceAssignment.setFake(true); newDirectAdvanceAssignment.setMaxValue(new BigDecimal(100)); newDirectAdvanceAssignment.setAdvanceType(indirectAdvanceAssignment.getAdvanceType()); newDirectAdvanceAssignment.setOrderElement(this); Set<DirectAdvanceAssignment> directAdvanceAssignments = new HashSet<>(); for (OrderElement orderElement : children) { directAdvanceAssignments.addAll(orderElement.getAllDirectAdvanceAssignmentsReportGlobal()); } List<AdvanceMeasurement> advanceMeasurements = new ArrayList<>(); for (DirectAdvanceAssignment directAdvanceAssignment : directAdvanceAssignments) { advanceMeasurements.addAll(directAdvanceAssignment.getAdvanceMeasurements()); } List<LocalDate> measurementDates = getMeasurementDates(advanceMeasurements); SortedSet<AdvanceMeasurement> newAdvanceMeasurements = new TreeSet<>(new AdvanceMeasurementComparator()); for (LocalDate localDate : measurementDates) { BigDecimal value = getAdvancePercentageChildren(localDate).multiply(new BigDecimal(100)); AdvanceMeasurement advanceMeasurement = AdvanceMeasurement.create(localDate, value); advanceMeasurement.setAdvanceAssignment(newDirectAdvanceAssignment); newAdvanceMeasurements.add(advanceMeasurement); } newDirectAdvanceAssignment.setAdvanceMeasurements(newAdvanceMeasurements); return newDirectAdvanceAssignment; } private List<LocalDate> getMeasurementDates(List<AdvanceMeasurement> advanceMeasurements) { List<LocalDate> result = new ArrayList<>(); for (AdvanceMeasurement advanceMeasurement : advanceMeasurements) { LocalDate date = advanceMeasurement.getDate(); if ( result.indexOf(date) < 0 ) { result.add(date); } } Collections.sort(result); return result; } private DirectAdvanceAssignment mergeAdvanceAssignments(List<DirectAdvanceAssignment> list) { if ( list.isEmpty() ) { return null; } Iterator<DirectAdvanceAssignment> iterator = list.iterator(); DirectAdvanceAssignment origAdvanceAssignment = iterator.next(); DirectAdvanceAssignment directAdvanceAssignment = DirectAdvanceAssignment.create(); directAdvanceAssignment.setFake(true); directAdvanceAssignment.setMaxValue(origAdvanceAssignment.getMaxValue()); directAdvanceAssignment.setAdvanceType(origAdvanceAssignment.getAdvanceType()); directAdvanceAssignment.setOrderElement(this); directAdvanceAssignment.setAdvanceMeasurements(origAdvanceAssignment.getAdvanceMeasurements()); while (iterator.hasNext()) { DirectAdvanceAssignment tempAssignment = iterator.next(); if ( !directAdvanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal maxValue = tempAssignment.getMaxValue(); maxValue = maxValue.add(directAdvanceAssignment.getMaxValue()); directAdvanceAssignment.setMaxValue(maxValue); } SortedSet<AdvanceMeasurement> advanceMeasurements = new TreeSet<>(new AdvanceMeasurementComparator()); advanceMeasurements.addAll(mergeAdvanceMeasurements( directAdvanceAssignment, new ArrayList<>(directAdvanceAssignment.getAdvanceMeasurements()), new ArrayList<>(tempAssignment.getAdvanceMeasurements()))); directAdvanceAssignment.setAdvanceMeasurements(advanceMeasurements); } return directAdvanceAssignment; } private List<AdvanceMeasurement> mergeAdvanceMeasurements(AdvanceAssignment advanceAssignment, List<AdvanceMeasurement> one, List<AdvanceMeasurement> other) { Collections.reverse(one); Collections.reverse(other); ArrayList<AdvanceMeasurement> list = new ArrayList<>(); mergeAdvanceMeasurements(advanceAssignment, one, other, list); return list; } private void mergeAdvanceMeasurements(AdvanceAssignment advanceAssignment, List<AdvanceMeasurement> list1, List<AdvanceMeasurement> list2, List<AdvanceMeasurement> result) { Iterator<AdvanceMeasurement> iterator1 = list1.iterator(); Iterator<AdvanceMeasurement> iterator2 = list2.iterator(); AdvanceMeasurement next1; if ( iterator1.hasNext() ) { next1 = iterator1.next(); } else { next1 = null; } AdvanceMeasurement next2; if ( iterator2.hasNext() ) { next2 = iterator2.next(); } else { next2 = null; } BigDecimal previous1 = BigDecimal.ZERO; BigDecimal previous2 = BigDecimal.ZERO; BigDecimal previousResult = BigDecimal.ZERO; LocalDate date; BigDecimal add; Date communicationDate; BigDecimal totalHours = null; if ( advanceAssignment.getAdvanceType().getPercentage() ) { totalHours = new BigDecimal(advanceAssignment.getOrderElement().getWorkHours()); } while ((next1 != null) && (next2 != null)) { if ( next1.getDate().compareTo(next2.getDate()) < 0 ) { date = next1.getDate(); add = next1.getValue().subtract(previous1); communicationDate = next1.getCommunicationDate(); previous1 = next1.getValue(); if ( advanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal orderElementHours = new BigDecimal(next1.getAdvanceAssignment().getOrderElement().getWorkHours()); add = addMeasure(add, totalHours, orderElementHours); } if ( iterator1.hasNext() ) { next1 = iterator1.next(); } else { next1 = null; } } else if ( next1.getDate().compareTo(next2.getDate() ) > 0) { date = next2.getDate(); add = next2.getValue().subtract(previous2); communicationDate = next2.getCommunicationDate(); previous2 = next2.getValue(); if ( advanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal orderElementHours = new BigDecimal(next2.getAdvanceAssignment().getOrderElement().getWorkHours()); add = addMeasure(add, totalHours, orderElementHours); } if ( iterator2.hasNext() ) { next2 = iterator2.next(); } else { next2 = null; } } else { date = next1.getDate(); BigDecimal add1 = next1.getValue().subtract(previous1); BigDecimal add2 = next2.getValue().subtract(previous2); add = add1.add(add2); communicationDate = getGreatestDate(next1.getCommunicationDate(), next2.getCommunicationDate()); previous1 = next1.getValue(); previous2 = next2.getValue(); if ( advanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal orderElementHours1 = new BigDecimal(next1.getAdvanceAssignment().getOrderElement().getWorkHours()); add1 = addMeasure(add1, totalHours, orderElementHours1); BigDecimal orderElementHours2 = new BigDecimal(next2.getAdvanceAssignment().getOrderElement().getWorkHours()); add2 = addMeasure(add2, totalHours, orderElementHours2); add = add1.add(add2); } if (iterator1.hasNext()) { next1 = iterator1.next(); } else { next1 = null; } if (iterator2.hasNext()) { next2 = iterator2.next(); } else { next2 = null; } } AdvanceMeasurement advanceMeasurement = AdvanceMeasurement.create(); advanceMeasurement.setAdvanceAssignment(advanceAssignment); advanceMeasurement.setDate(date); previousResult = previousResult.add(add); checkAndSetValue(advanceMeasurement, previousResult); advanceMeasurement.setCommunicationDate(communicationDate); result.add(advanceMeasurement); } while (next1 != null) { date = next1.getDate(); add = next1.getValue().subtract(previous1); communicationDate = next1.getCommunicationDate(); previous1 = next1.getValue(); if ( advanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal orderElementHours = new BigDecimal(next1.getAdvanceAssignment().getOrderElement().getWorkHours()); add = addMeasure(add, totalHours, orderElementHours); } if ( iterator1.hasNext() ) { next1 = iterator1.next(); } else { next1 = null; } AdvanceMeasurement advanceMeasurement = AdvanceMeasurement.create(); advanceMeasurement.setAdvanceAssignment(advanceAssignment); advanceMeasurement.setDate(date); checkAndSetValue(advanceMeasurement, previousResult.add(add)); previousResult = advanceMeasurement.getValue(); advanceMeasurement.setCommunicationDate(communicationDate); result.add(advanceMeasurement); } while (next2 != null) { date = next2.getDate(); add = next2.getValue().subtract(previous2); communicationDate = next2.getCommunicationDate(); previous2 = next2.getValue(); if ( advanceAssignment.getAdvanceType().getPercentage() ) { BigDecimal orderElementHours = new BigDecimal(next2.getAdvanceAssignment().getOrderElement().getWorkHours()); add = addMeasure(add, totalHours, orderElementHours); } if ( iterator2.hasNext() ) { next2 = iterator2.next(); } else { next2 = null; } AdvanceMeasurement advanceMeasurement = AdvanceMeasurement.create(); advanceMeasurement.setAdvanceAssignment(advanceAssignment); advanceMeasurement.setDate(date); checkAndSetValue(advanceMeasurement, previousResult.add(add)); previousResult = advanceMeasurement.getValue(); advanceMeasurement.setCommunicationDate(communicationDate); result.add(advanceMeasurement); } } private void checkAndSetValue(AdvanceMeasurement advanceMeasurement, BigDecimal previousResult) { advanceMeasurement.setValue(previousResult); if ( !advanceMeasurement.isValidPrecisionConstraint() ) { AdvanceAssignment advanceAssignment = advanceMeasurement.getAdvanceAssignment(); boolean condition = (previousResult == null) || (advanceAssignment == null) || (advanceAssignment.getAdvanceType() == null); if ( condition ) { return; } BigDecimal precision = advanceAssignment.getAdvanceType().getUnitPrecision(); BigDecimal result[] = previousResult.divideAndRemainder(precision); BigDecimal checkResult; if ( previousResult.compareTo(result[1]) >= 0 ) { checkResult = previousResult.subtract(result[1]); } else { checkResult = previousResult.add(result[1]); } advanceMeasurement.setValue(checkResult); } } private BigDecimal addMeasure(BigDecimal add, BigDecimal totalHours, BigDecimal orderElementHours) { if ( (totalHours != null) && (totalHours.compareTo(BigDecimal.ZERO) > 0) ) { add = add.multiply(orderElementHours).divide(totalHours, RoundingMode.DOWN); } else { add = add.multiply(orderElementHours); } return add; } private Date getGreatestDate(Date communicationDate, Date communicationDate2) { if ((communicationDate == null) || (communicationDate2 == null)) { return null; } return (communicationDate.compareTo(communicationDate2) >= 0) ? communicationDate : communicationDate2; } @Override public Set<DirectAdvanceAssignment> getAllDirectAdvanceAssignments(AdvanceType advanceType) { Set<DirectAdvanceAssignment> result = new HashSet<>(); for (DirectAdvanceAssignment directAdvanceAssignment : directAdvanceAssignments) { if ( directAdvanceAssignment.getAdvanceType().getUnitName().equals(advanceType.getUnitName()) ) { result.add(directAdvanceAssignment); return result; } } for (OrderElement orderElement : children) { result.addAll(orderElement.getAllDirectAdvanceAssignments(advanceType)); } return result; } @Override public Set<IndirectAdvanceAssignment> getAllIndirectAdvanceAssignments(AdvanceType advanceType) { Set<IndirectAdvanceAssignment> result = new HashSet<>(); IndirectAdvanceAssignment indirectAdvanceAssignment = getIndirectAdvanceAssignment(advanceType); if ( indirectAdvanceAssignment != null ) { result.add(indirectAdvanceAssignment); } for (OrderElement orderElement : children) { result.addAll(orderElement.getAllIndirectAdvanceAssignments(advanceType)); } return result; } public IndirectAdvanceAssignment getIndirectAdvanceAssignment(AdvanceType advanceType) { for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) { if ( indirectAdvanceAssignment.getAdvanceType().getUnitName().equals(advanceType.getUnitName()) ) { return indirectAdvanceAssignment; } } return null; } @Override protected Set<DirectAdvanceAssignment> getAllDirectAdvanceAssignmentsReportGlobal() { Set<DirectAdvanceAssignment> result = new HashSet<>(); for (DirectAdvanceAssignment directAdvanceAssignment : directAdvanceAssignments) { if ( directAdvanceAssignment.getReportGlobalAdvance() ) { result.add(directAdvanceAssignment); } } for (OrderElement orderElement : children) { result.addAll(orderElement.getAllDirectAdvanceAssignmentsReportGlobal()); } return result; } @Override protected Set<DirectAdvanceAssignment> getAllDirectAdvanceAssignments() { Set<DirectAdvanceAssignment> result = new HashSet<>(); result.addAll(directAdvanceAssignments); for (OrderElement orderElement : children) { result.addAll(orderElement.getAllDirectAdvanceAssignments()); } return result; } @Override public Set<IndirectAdvanceAssignment> getIndirectAdvanceAssignments() { return Collections.unmodifiableSet(indirectAdvanceAssignments); } public void addIndirectAdvanceAssignment(IndirectAdvanceAssignment indirectAdvanceAssignment) { if ( (!existsIndirectAdvanceAssignmentWithTheSameType(indirectAdvanceAssignment.getAdvanceType())) && (!existsDirectAdvanceAssignmentWithTheSameType(indirectAdvanceAssignment.getAdvanceType())) ) { indirectAdvanceAssignments.add(indirectAdvanceAssignment); } if ( parent != null ) { parent.addIndirectAdvanceAssignment(indirectAdvanceAssignment.createIndirectAdvanceFor(parent)); } } public void removeIndirectAdvanceAssignment(AdvanceType advanceType) { DirectAdvanceAssignment tempAdvanceAssignment = DirectAdvanceAssignment.create(); tempAdvanceAssignment.setAdvanceType(advanceType); try { checkChildrenNoOtherAssignmentWithSameAdvanceType(this, tempAdvanceAssignment); String unitName = advanceType.getUnitName(); IndirectAdvanceAssignment toRemove = null; for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) { if ( unitName.equals(indirectAdvanceAssignment.getAdvanceType().getUnitName()) ) { toRemove = indirectAdvanceAssignment; } } if ( toRemove != null ) { indirectAdvanceAssignments.remove(toRemove); updateSpreadAdvance(); } if ( parent != null ) { parent.removeIndirectAdvanceAssignment(advanceType); } } catch (DuplicateAdvanceAssignmentForOrderElementException e) { // If exist another DirectAdvanceAssignment with the same // AdvanceType in some children, the IndirectAdvanceAssignment // should persist } } public boolean existsIndirectAdvanceAssignmentWithTheSameType(AdvanceType type) { String unitName = type.getUnitName(); for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) { if ( unitName.equals(indirectAdvanceAssignment.getAdvanceType().getUnitName()) ) { return true; } } return false; } @Override protected void checkNoOtherGlobalAdvanceAssignment(DirectAdvanceAssignment newAdvanceAssignment) throws DuplicateValueTrueReportGlobalAdvanceException { if ( !newAdvanceAssignment.getReportGlobalAdvance() ) { return; } Set<AdvanceAssignment> advanceAssignments = new HashSet<>(); advanceAssignments.addAll(directAdvanceAssignments); advanceAssignments.addAll(indirectAdvanceAssignments); for (AdvanceAssignment advanceAssignment : advanceAssignments) { if ( advanceAssignment.getReportGlobalAdvance() ) { throw new DuplicateValueTrueReportGlobalAdvanceException( _("Cannot spread two progress in the same task"), this, OrderElement.class); } } } protected void copyRequirementToOrderElement(OrderLine leaf) { criterionRequirementHandler.copyRequirementToOrderLine(this, leaf); } @Override public DirectAdvanceAssignment getReportGlobalAdvanceAssignment() { for (DirectAdvanceAssignment directAdvanceAssignment : getDirectAdvanceAssignments()) { if ( directAdvanceAssignment.getReportGlobalAdvance() ) { return directAdvanceAssignment; } } for (IndirectAdvanceAssignment indirectAdvanceAssignment : getIndirectAdvanceAssignments()) { if ( indirectAdvanceAssignment.getReportGlobalAdvance() ) { return calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment); } } return null; } @Override public void removeReportGlobalAdvanceAssignment() { Set<AdvanceAssignment> advanceAssignments = new HashSet<>(); advanceAssignments.addAll(getDirectAdvanceAssignments()); advanceAssignments.addAll(getIndirectAdvanceAssignments()); AdvanceAssignment advanceAssignment = null; for (AdvanceAssignment each : advanceAssignments) { if ( each.getReportGlobalAdvance() ) { advanceAssignment = each; } } if ( advanceAssignment != null ) { advanceAssignment.setReportGlobalAdvance(false); } markAsDirtyLastAdvanceMeasurementForSpreading(); } public DirectAdvanceAssignment getAdvanceAssignmentByType(AdvanceType type) { DirectAdvanceAssignment result = getDirectAdvanceAssignmentByType(type); if ( result != null ) { return result; } for (IndirectAdvanceAssignment each : getIndirectAdvanceAssignments()) { if ( type != null && each.getAdvanceType().getId().equals(type.getId()) ) { return calculateFakeDirectAdvanceAssignment(each); } } return null; } @Override public OrderElementTemplate createTemplate() { return OrderLineGroupTemplate.create(this); } @Override public OrderLineGroup getThis() { return this; } @Override public OrderLine calculateOrderLineForSubcontract() { OrderLine orderLine = OrderLine.create(); orderLine.setCode(getCode()); orderLine.setName(getName()); orderLine.setDescription(getDescription()); orderLine.setInitDate(getInitDate()); orderLine.setDeadline(getDeadline()); // HoursGroups from all its child nodes for (HoursGroup hoursGroup : getHoursGroups()) { orderLine.addHoursGroup(hoursGroup); } // CriterionRequirements from this node orderLine.setCriterionRequirements(getCriterionRequirements()); // Labels from this node orderLine.setLabels(getLabels()); // MaterialAssignments from this node and all its child nodes for (MaterialAssignment materialAssignment : getMaterialAssignments()) { orderLine.addMaterialAssignment(materialAssignment); } return orderLine; } public OrderVersion getCurrentOrderVersion() { return getCurrentSchedulingData().getOriginOrderVersion(); } public OrderElement findRepeatedOrderCode() { Set<String> codes = new HashSet<>(); codes.add(getCode()); for (OrderElement each : getAllOrderElements()) { String code = each.getCode(); if ( code != null && !code.isEmpty() ) { if ( codes.contains(code) ) { return each; } codes.add(code); } } return null; } public HoursGroup findRepeatedHoursGroupCode() { Set<String> codes = new HashSet<>(); for (HoursGroup hoursGroup : getHoursGroups()) { String code = hoursGroup.getCode(); if ( code != null && !code.isEmpty() ) { if ( codes.contains(code) ) { return hoursGroup; } codes.add(code); } } return null; } public List<OrderElement> getAllOrderElements() { List<OrderElement> result = new ArrayList<>(this.getChildren()); for (OrderElement orderElement : this.getChildren()) { result.addAll(orderElement.getAllChildren()); } return result; } @AssertTrue(message = "indirect progress assignments should have different types") public boolean isIndirectAdvanceAssignmentsWithDifferentTypeConstraint() { Set<String> types = new HashSet<>(); for (IndirectAdvanceAssignment each : indirectAdvanceAssignments) { String type = each.getAdvanceType().getUnitName(); if ( types.contains(type) ) { return false; } types.add(type); } return true; } @Override public BigDecimal getBudget() { BigDecimal budget = BigDecimal.ZERO.setScale(2); for (OrderElement child : children) { budget = budget.add(child.getBudget()); } return budget; } }