/* * 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-2011 Igalia, S.L. * * Copyright (C) 2011-2012 WirelessGalicia, 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.web.orders; import static org.libreplan.web.I18nHelper._; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; 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 org.apache.commons.lang3.Validate; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.joda.time.LocalDate; import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes; import org.libreplan.business.advance.daos.IAdvanceMeasurementDAO; import org.libreplan.business.advance.daos.IAdvanceTypeDAO; 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.common.exceptions.InstanceNotFoundException; import org.libreplan.business.orders.daos.IOrderElementDAO; import org.libreplan.business.orders.entities.Order; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.planner.entities.TaskElement; import org.libreplan.business.planner.entities.consolidations.CalculatedConsolidatedValue; import org.libreplan.business.planner.entities.consolidations.CalculatedConsolidation; import org.libreplan.business.planner.entities.consolidations.Consolidation; import org.libreplan.business.planner.entities.consolidations.NonCalculatedConsolidatedValue; import org.libreplan.business.planner.entities.consolidations.NonCalculatedConsolidation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.zkoss.zul.SimpleXYModel; import org.zkoss.zul.XYModel; /** * Service to manage the advance of a selected order element. * * @author Susana Montes Pedreira <smontes@wirelessgalicia.com> * @author Diego Pino García <dpino@igalia.com> */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) public class ManageOrderElementAdvancesModel implements IManageOrderElementAdvancesModel { private static final Log LOG = LogFactory.getLog(ManageOrderElementAdvancesModel.class); @Autowired private final IAdvanceTypeDAO advanceTypeDAO; @Autowired private final IOrderElementDAO orderElementDAO; private OrderElement orderElement; private DirectAdvanceAssignment advanceAssignment; private boolean isIndirectAdvanceAssignment = false; private List<AdvanceAssignment> listAdvanceAssignments; private List<AdvanceType> listAdvanceTypes; @Autowired public ManageOrderElementAdvancesModel( IAdvanceMeasurementDAO advanceMeasurementDAO, IAdvanceTypeDAO advanceTypeDAO, IOrderElementDAO orderElementDAO) { Validate.notNull(advanceMeasurementDAO); this.advanceTypeDAO = advanceTypeDAO; this.orderElementDAO = orderElementDAO; } @Override public String getInfoAdvanceAssignment(){ if (this.advanceAssignment == null || this.orderElement == null) { return ""; } return getInfoAdvanceAssignment(this.advanceAssignment); } private String getInfoAdvanceAssignment(DirectAdvanceAssignment assignment) { if (assignment == null) { return ""; } if ((assignment.getAdvanceType() == null) || assignment.getMaxValue() == null) { return ""; } return _("{0} (max: {1})", assignment.getAdvanceType().getUnitName(), assignment.getMaxValue()); } @Override @Transactional(readOnly = true) public List<AdvanceMeasurement> getAdvanceMeasurements() { if (this.advanceAssignment == null || this.orderElement == null) { return new ArrayList<>(); } return new ArrayList<>(this.advanceAssignment.getAdvanceMeasurements()); } @Override @Transactional(readOnly = true) public List<AdvanceAssignment> getAdvanceAssignments() { if (orderElement == null) { return new ArrayList<>(); } return listAdvanceAssignments; } @Override public void refreshChangesFromOrderElement() { List<AdvanceAssignment> listAdvanceAssignmentsCopy = new ArrayList<>(listAdvanceAssignments); fillAdvanceAssignmentList(); for (AdvanceAssignment advance : listAdvanceAssignmentsCopy) { if ( (!listAdvanceAssignments.contains(advance)) && (advance instanceof DirectAdvanceAssignment) && (!advance.getAdvanceType().isQualityForm()) && (!advance.getAdvanceType().isReadOnly()) ) { listAdvanceAssignments.add(advance); } } } @Override public void prepareEditAdvanceMeasurements(AdvanceAssignment assignment) { if (assignment instanceof IndirectAdvanceAssignment) { this.advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment((IndirectAdvanceAssignment) assignment); this.isIndirectAdvanceAssignment = true; } else { if (assignment instanceof DirectAdvanceAssignment) { this.advanceAssignment = (DirectAdvanceAssignment) assignment; this.isIndirectAdvanceAssignment = false; } } } @Override @Transactional(readOnly = true) public void initEdit(OrderElement orderElement) { this.orderElement = orderElement; this.advanceAssignment = null; if (orderElement != null){ loadAdvanceTypes(); reattachmentOrderElement(); forceLoadAdvanceAssignmentsAndMeasurements(); fillAdvanceAssignmentList(); } } private void forceLoadAdvanceAssignmentsAndMeasurements() { for (DirectAdvanceAssignment each : orderElement.getDirectAdvanceAssignments()) { forceLoadAdvanceConsolidatedValues(each); each.getNonCalculatedConsolidation().size(); each.getAdvanceType().getUnitName(); } for (IndirectAdvanceAssignment each : orderElement.getIndirectAdvanceAssignments()) { each.getCalculatedConsolidation().size(); each.getAdvanceType().getUnitName(); DirectAdvanceAssignment fakedDirect = orderElement.calculateFakeDirectAdvanceAssignment(each); if (fakedDirect != null) { forceLoadAdvanceConsolidatedValues(fakedDirect); } else { LOG.warn("Fake direct advance assignment shouldn't be NULL for type '" + each.getAdvanceType().getUnitName() + "'"); } } } private void forceLoadAdvanceConsolidatedValues(DirectAdvanceAssignment advance) { for (AdvanceMeasurement measurement : advance.getAdvanceMeasurements()) { for (NonCalculatedConsolidatedValue each : measurement.getNonCalculatedConsolidatedValues()) { each.getConsolidation().getConsolidatedUntil(); } } } public void reattachmentOrderElement() { orderElementDAO.reattach(orderElement); } private void fillAdvanceAssignmentList() { listAdvanceAssignments = new ArrayList<>(); for (DirectAdvanceAssignment each : orderElement.getDirectAdvanceAssignments()) { listAdvanceAssignments.add(each); } for (IndirectAdvanceAssignment each : orderElement.getIndirectAdvanceAssignments()) { listAdvanceAssignments.add(each); } } @Override public boolean addNewLineAdvanceAssignment() { DirectAdvanceAssignment newAdvance = DirectAdvanceAssignment.create(); newAdvance.setOrderElement(orderElement); // Set first advance type of the list as default List<AdvanceType> listAdvanceType = getPossibleAdvanceTypes(newAdvance); if (listAdvanceType.isEmpty()) { return false; } // Create new progress type and add it to list final AdvanceType progressType = first(listAdvanceType); newAdvance.setAdvanceType(progressType); newAdvance.setMaxValue(getMaxValue(progressType)); newAdvance.setReportGlobalAdvance(listAdvanceAssignments.isEmpty()); listAdvanceAssignments.add(newAdvance); return true; } private AdvanceType first(List<AdvanceType> listAdvanceType) { return listAdvanceType.get(0); } @Override public BigDecimal getMaxValue(AdvanceType advanceType) { if (advanceType != null) { return advanceType.getDefaultMaxValue(); } return BigDecimal.ZERO; } @Override public AdvanceAssignment getSpreadAdvance() { for (AdvanceAssignment advance : getAdvanceAssignments()) { if (advance.getReportGlobalAdvance()) { return advance; } } return null; } @Override public AdvanceMeasurement addNewLineAdvanceMeasurement() { if (advanceAssignment != null) { AdvanceMeasurement newMeasurement = createMeasurement(); addMeasurement(newMeasurement); return newMeasurement; } return null; } private AdvanceMeasurement createMeasurement() { AdvanceMeasurement result = AdvanceMeasurement.create(); result.setDate(new LocalDate()); result.setAdvanceAssignment(advanceAssignment); return result; } private void addMeasurement(AdvanceMeasurement measurement) { if (!advanceAssignment.addAdvanceMeasurements(measurement)) { measurement.setDate(null); advanceAssignment.addAdvanceMeasurements(measurement); } } @Override public void removeLineAdvanceAssignment(AdvanceAssignment advance) { advance.setOrderElement(null); this.listAdvanceAssignments.remove(advance); orderElement.removeAdvanceAssignment(advance); this.advanceAssignment = null; } @Override public void removeLineAdvanceMeasurement(AdvanceMeasurement measurement) { this.advanceAssignment.removeAdvanceMeasurement(measurement); } @Override public List<AdvanceType> getPossibleAdvanceTypes(DirectAdvanceAssignment directAdvanceAssignment) { if (orderElement == null) { return new ArrayList<>(); } List<AdvanceType> advanceTypes = new ArrayList<>(); for (AdvanceType advanceType : this.listAdvanceTypes) { if ( (advanceType.getUnitName().equals(PredefinedAdvancedTypes.CHILDREN.getTypeName())) || (advanceType.isQualityForm()) || advanceType.isReadOnly() ) { continue; } if (existsAdvanceTypeAlreadyInThisOrderElement(advanceType)) { if ( (directAdvanceAssignment.getAdvanceType() == null) || (!directAdvanceAssignment.getAdvanceType().getUnitName().equals(advanceType.getUnitName())) ) { continue; } } // If the associated task of the order element or of some its children is subcontracted // the advance type subcontractor is not permitted if (advanceType.getUnitName() .equals(PredefinedAdvancedTypes.SUBCONTRACTOR.getTypeName()) && hasAnySubcontractedTaskOnChildren()) { continue; } advanceTypes.add(advanceType); } return getSpecificOrder(advanceTypes); } private List<AdvanceType> getSpecificOrder(List<AdvanceType> advanceTypes ) { Collections.sort(advanceTypes, new Comparator<AdvanceType>() { @Override public int compare(AdvanceType arg0, AdvanceType arg1) { if ((arg0 == null) || (arg0.getUnitName() == null)) { return -1; } if ((arg1 == null) || (arg1.getUnitName() == null) || (arg1.getUnitName().equals(PredefinedAdvancedTypes.PERCENTAGE.getTypeName()))) { return 1; } if (arg0.getUnitName().equals(PredefinedAdvancedTypes.PERCENTAGE.getTypeName())) { return -1; } return (arg0.getUnitName().compareTo(arg1.getUnitName())); } }); return advanceTypes; } private boolean existsAdvanceTypeAlreadyInThisOrderElement(AdvanceType advanceType) { if (listAdvanceAssignments != null) { for (AdvanceAssignment each : listAdvanceAssignments) { if ( (each.getAdvanceType() != null) && (each.getAdvanceType().getUnitName().equals(advanceType.getUnitName())) ) { return true; } } } return false; } @Transactional(readOnly = true) private void loadAdvanceTypes() { this.listAdvanceTypes = this.advanceTypeDAO.findActivesAdvanceTypes(); } @Override public boolean isReadOnlyAdvanceMeasurements() { if ( this.advanceAssignment == null ) { return true; } AdvanceType advanceType = this.advanceAssignment.getAdvanceType(); if ( advanceType != null ) { if ( advanceType.isQualityForm() ) { return true; } if ( advanceType.isReadOnly() ) { return true; } } return isIndirectAdvanceAssignment || isSubcontractedAdvanceTypeAndSubcontractedTask(advanceAssignment); } @Override public boolean isSubcontractedAdvanceTypeAndSubcontractedTask(AdvanceAssignment advance) { return (isSubcontractedAdvanceType(advance) && hasSubcontractedAssociatedTask(advance.getOrderElement())); } @Override public boolean isSubcontractedAdvanceType(AdvanceAssignment advance) { AdvanceType advanceType = advance.getAdvanceType(); if (advanceType != null) { if (advanceType.getUnitName().equals(PredefinedAdvancedTypes.SUBCONTRACTOR.getTypeName())) { return true; } } return false; } @Override public void cleanAdvance(DirectAdvanceAssignment advanceAssignment) { if (advanceAssignment != null) { advanceAssignment.clearAdvanceMeasurements(); } } @Override public void resetAdvanceAssignment() { this.advanceAssignment = null; } @Override @Transactional(readOnly = true) public void confirmSave() throws InstanceNotFoundException, DuplicateAdvanceAssignmentForOrderElementException, DuplicateValueTrueReportGlobalAdvanceException { reattachmentOrderElement(); orderElement.updateAdvancePercentageTaskElement(); validateBasicData(); } private void validateBasicData() throws InstanceNotFoundException, DuplicateAdvanceAssignmentForOrderElementException, DuplicateValueTrueReportGlobalAdvanceException { updateRemoveAdvances(); for (AdvanceAssignment each : this.listAdvanceAssignments) { if (each instanceof DirectAdvanceAssignment) { validateBasicData((DirectAdvanceAssignment) each); } } } private void updateRemoveAdvances(){ for (AdvanceAssignment each : this.listAdvanceAssignments) { AdvanceAssignment advance = yetExistAdvanceAssignment(each); if (advance == null) { removeAdvanceAssignment(each); } } } private void validateBasicData(DirectAdvanceAssignment directAdvanceAssignment) throws InstanceNotFoundException, DuplicateAdvanceAssignmentForOrderElementException, DuplicateValueTrueReportGlobalAdvanceException { if (directAdvanceAssignment.getVersion() == null) { addAdvanceAssignment(directAdvanceAssignment); } } private AdvanceAssignment yetExistAdvanceAssignment(AdvanceAssignment assignment) { for (AdvanceAssignment advance : this.orderElement.getDirectAdvanceAssignments()) { if (advance.getVersion() != null && advance.getId().equals(assignment.getId())) { return advance; } } return null; } @Transactional(readOnly = true) private void addAdvanceAssignment(DirectAdvanceAssignment newAdvanceAssignment) throws DuplicateAdvanceAssignmentForOrderElementException, DuplicateValueTrueReportGlobalAdvanceException { if (newAdvanceAssignment.getReportGlobalAdvance()) { this.orderElement.removeReportGlobalAdvanceAssignment(); } this.orderElement.addAdvanceAssignment(newAdvanceAssignment); } private void removeAdvanceAssignment(AdvanceAssignment assignment) { if (assignment != null) { orderElement.removeAdvanceAssignment(assignment); } } @Override public boolean isPrecisionValid(AdvanceMeasurement advanceMeasurement) { if ((this.advanceAssignment != null) && (this.advanceAssignment.getAdvanceType() != null)) { return advanceMeasurement.isValidPrecisionConstraint(); } return true; } @Override public boolean greatThanMaxValue(AdvanceMeasurement advanceMeasurement) { if (this.advanceAssignment == null || this.advanceAssignment.getMaxValue() == null) { return false; } return !(advanceMeasurement.isValueIsLessThanMaxValueConstraint()); } @Override public boolean lessThanPreviousMeasurements() { if (this.advanceAssignment == null) { return false; } return !(this.advanceAssignment.isValidAdvanceMeasurementsConstraint()); } @Override public boolean isDistinctValidDate(LocalDate value, AdvanceMeasurement newAdvanceMeasurement) { if (this.advanceAssignment == null) { return true; } for (AdvanceMeasurement advanceMeasurement : advanceAssignment.getAdvanceMeasurements()) { LocalDate oldDate = advanceMeasurement.getDate(); if (oldDate != null && !newAdvanceMeasurement.equals(advanceMeasurement) && oldDate.compareTo(new LocalDate(value)) == 0) { return false; } } return true; } @Override public BigDecimal getUnitPrecision(){ if (this.advanceAssignment == null) { return BigDecimal.ZERO; } return this.advanceAssignment.getAdvanceType().getUnitPrecision(); } @Override @Transactional(readOnly = true) public AdvanceMeasurement getLastAdvanceMeasurement(DirectAdvanceAssignment assignment) { if (assignment != null) { SortedSet<AdvanceMeasurement> advanceMeasurements = assignment.getAdvanceMeasurements(); if (advanceMeasurements.size() > 0) { return advanceMeasurements.first(); } } return null; } @Override public void sortListAdvanceMeasurement() { if (advanceAssignment != null) { ArrayList<AdvanceMeasurement> advanceMeasurements = new ArrayList<>(advanceAssignment.getAdvanceMeasurements()); Collections.sort(advanceMeasurements, new AdvanceMeasurementComparator()); TreeSet<AdvanceMeasurement> measurements = new TreeSet<>(new AdvanceMeasurementComparator()); measurements.addAll(advanceMeasurements); this.advanceAssignment.setAdvanceMeasurements(measurements); } } @Override public BigDecimal getPercentageAdvanceMeasurement(AdvanceMeasurement advanceMeasurement) { AdvanceAssignment assignment = advanceMeasurement.getAdvanceAssignment(); if (assignment == null) { return BigDecimal.ZERO; } BigDecimal maxValue; if (assignment instanceof IndirectAdvanceAssignment) { maxValue = orderElement .calculateFakeDirectAdvanceAssignment((IndirectAdvanceAssignment) assignment).getMaxValue(); } else { maxValue = ((DirectAdvanceAssignment) assignment).getMaxValue(); } if (maxValue.compareTo(BigDecimal.ZERO) <= 0) { return BigDecimal.ZERO; } BigDecimal value = advanceMeasurement.getValue(); if (value == null) { return BigDecimal.ZERO; } BigDecimal division = value.divide(maxValue.setScale(2), 4, RoundingMode.DOWN); return (division.multiply(new BigDecimal(100))).setScale(2, RoundingMode.DOWN); } @Override @Transactional(readOnly = true) public DirectAdvanceAssignment calculateFakeDirectAdvanceAssignment(IndirectAdvanceAssignment indirectAdvanceAssignment) { if ((orderElement == null) || (orderElement.isLeaf())) { return null; } reattachmentOrderElement(); return orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment); } @Override @Transactional(readOnly = true) public BigDecimal getAdvancePercentageChildren() { if ((orderElement == null) || orderElement.isLeaf()) { return null; } reattachmentOrderElement(); return orderElement.getAdvancePercentageChildren(); } @Override @Transactional(readOnly = true) public XYModel getChartData(Set<AdvanceAssignment> selectedAdvances) { XYModel xyModel = new SimpleXYModel(); for (AdvanceAssignment each : selectedAdvances) { DirectAdvanceAssignment directAdvanceAssignment; if (each instanceof DirectAdvanceAssignment) { directAdvanceAssignment = (DirectAdvanceAssignment) each; } else { directAdvanceAssignment = calculateFakeDirectAdvanceAssignment((IndirectAdvanceAssignment) each); } if (directAdvanceAssignment != null) { String title = getInfoAdvanceAssignment(directAdvanceAssignment); SortedSet<AdvanceMeasurement> listAdvanceMeasurements = directAdvanceAssignment.getAdvanceMeasurements(); if (listAdvanceMeasurements.size() > 1) { for (AdvanceMeasurement advanceMeasurement : listAdvanceMeasurements) { BigDecimal value = advanceMeasurement.getValue(); if ((selectedAdvances.size() > 1) && (value != null) && (value.compareTo(BigDecimal.ZERO) > 0)) { BigDecimal maxValue = directAdvanceAssignment.getMaxValue(); value = value.setScale(2).divide(maxValue, RoundingMode.DOWN); } LocalDate date = advanceMeasurement.getDate(); if ((value != null) && (date != null)) { xyModel.addValue(title, date.toDateTimeAtStartOfDay().getMillis(), value); } } } } } return xyModel; } @Override @Transactional(readOnly = true) public boolean hasConsolidatedAdvances(AdvanceAssignment advance) { if (advance instanceof DirectAdvanceAssignment) { if ((advance.getReportGlobalAdvance()) && (!((DirectAdvanceAssignment) advance).getNonCalculatedConsolidation().isEmpty())) { return true; } return ((!((DirectAdvanceAssignment) advance).isFake()) && (!canBeRemovedAllAdvanceMeasurements((DirectAdvanceAssignment) advance))); } else { return ((advance.getReportGlobalAdvance()) && (!((IndirectAdvanceAssignment) advance).getCalculatedConsolidation().isEmpty())); } } private boolean canBeRemovedAllAdvanceMeasurements(DirectAdvanceAssignment advance) { Iterator<AdvanceMeasurement> iterator = advance.getAdvanceMeasurements().iterator(); while (iterator.hasNext()) { if (!canRemoveOrChange(iterator.next())) { return false; } } return true; } @Transactional(readOnly = true) public boolean canRemoveOrChange(AdvanceMeasurement advanceMeasurement) { return (!hasConsolidatedAdvances(advanceMeasurement) && !isAlreadyReportedProgress(advanceMeasurement)); } @Transactional(readOnly = true) public boolean hasConsolidatedAdvances(AdvanceMeasurement advanceMeasurement) { return hasConsolidatedAdvances(advanceMeasurement, isIndirectAdvanceAssignment); } private boolean hasConsolidatedAdvances(AdvanceMeasurement advanceMeasurement, boolean isIndirectAdvanceAssignment) { if (isIndirectAdvanceAssignment) { return false; } if (!advanceMeasurement.getNonCalculatedConsolidatedValues().isEmpty()) { return true; } return findIndirectConsolidation(advanceMeasurement); } @Override @Transactional(readOnly = true) public boolean isQualityForm(AdvanceAssignment advance) { AdvanceType advanceType = advance.getAdvanceType(); advanceTypeDAO.reattach(advanceType); return advanceType.isQualityForm(); } @Override @Transactional(readOnly = true) public boolean isReadOnly(AdvanceAssignment advance) { AdvanceType advanceType = advance.getAdvanceType(); advanceTypeDAO.reattach(advanceType); return advanceType.isReadOnly(); } @Override @Transactional(readOnly = true) public boolean findIndirectConsolidation(AdvanceMeasurement advanceMeasurement) { AdvanceAssignment advance = advanceMeasurement.getAdvanceAssignment(); if ((orderElement != null) && (orderElement.getParent() != null) && (advance instanceof DirectAdvanceAssignment)) { orderElementDAO.reattach(orderElement); Set<IndirectAdvanceAssignment> indirects = getSpreadIndirectAdvanceAssignmentWithSameType( orderElement, advance); for (IndirectAdvanceAssignment indirect : indirects) { if (findConsolidatedAdvance(indirect.getCalculatedConsolidation(), advanceMeasurement)) { return true; } } } return false; } private Set<IndirectAdvanceAssignment> getSpreadIndirectAdvanceAssignmentWithSameType(OrderElement orderElement, AdvanceAssignment advance) { List<String> types = new ArrayList<>(); types.add(advance.getAdvanceType().getUnitName()); if (advance.getReportGlobalAdvance()) { types.add(PredefinedAdvancedTypes.CHILDREN.getTypeName()); } return getSpreadIndirectAdvanceAssignmentWithSameType(orderElement, types); } private Set<IndirectAdvanceAssignment> getSpreadIndirectAdvanceAssignmentWithSameType(OrderElement orderElement, List<String> types) { Set<IndirectAdvanceAssignment> result = new HashSet<>(); for (IndirectAdvanceAssignment indirect : orderElement.getIndirectAdvanceAssignments()) { if ((indirect.getReportGlobalAdvance()) && (types.contains(indirect.getAdvanceType().getUnitName()))) { result.add(indirect); } } OrderElement parent = orderElement.getParent(); if (parent != null) { result.addAll(getSpreadIndirectAdvanceAssignmentWithSameType(parent, types)); } return result; } private boolean findConsolidatedAdvance(Set<CalculatedConsolidation> consolidations, AdvanceMeasurement advance) { for (CalculatedConsolidation consolidation : consolidations) { for (CalculatedConsolidatedValue value : consolidation.getCalculatedConsolidatedValues()) { if ((value.getDate() != null) && (advance.getDate() != null) && (value.getDate().compareTo(advance.getDate()) == 0)) { return true; } } } return false; } @Override public LocalDate getLastConsolidatedMeasurementDate(AdvanceAssignment advance) { List<Consolidation> consolidations = new ArrayList<>(); Set<NonCalculatedConsolidation> nonCalculatedConsolidations = ((DirectAdvanceAssignment) advance).getNonCalculatedConsolidation(); consolidations.addAll(nonCalculatedConsolidations); if (consolidations.isEmpty()) { Set<IndirectAdvanceAssignment> indirects = getSpreadIndirectAdvanceAssignmentWithSameType(orderElement, advance); for (IndirectAdvanceAssignment indirect : indirects) { consolidations.addAll(indirect.getCalculatedConsolidation()); } } if (consolidations.isEmpty()) { return null; } Collections.sort(consolidations, new Comparator<Consolidation>() { @Override public int compare(Consolidation o1, Consolidation o2) { return o1.getConsolidatedUntil().compareTo(o2.getConsolidatedUntil()); } }); return consolidations.get(consolidations.size() - 1).getConsolidatedUntil(); } @Override public boolean hasAnyConsolidatedAdvanceCurrentOrderElement() { return orderElement != null && orderElement.hasAnyConsolidatedAdvance(); } @Override public boolean hasAnySubcontractedTaskOnChildren() { List<OrderElement> list = new ArrayList<>(); list.add(orderElement); list.addAll(orderElement.getAllChildren()); for (OrderElement child : list) { if (hasSubcontractedAssociatedTask(child)) { return true; } } return false; } public boolean hasSubcontractedAssociatedTask(OrderElement orderElement) { for (TaskElement task : orderElement.getTaskElements()) { if (task.isSubcontracted()) { return true; } } return false; } @Override public Boolean isAlreadyReportedProgress(AdvanceMeasurement measure) { if (measure != null && !measure.isNewObject()) { return isAlreadyReportedProgressWith(measure.getDate()); } return false; } @Override public Boolean isAlreadyReportedProgressWith(LocalDate date) { if (isSubcontractedByCustomer() && isSubcontractedAdvanceType(advanceAssignment)) { LocalDate lastReported = getLastReportedProgressToCustomer(); return (date != null && lastReported != null && date.compareTo(lastReported) <= 0); } return false; } private LocalDate getLastReportedProgressToCustomer() { return getLastReportedProgressToCustomerOf(advanceAssignment); } private LocalDate getLastReportedProgressToCustomerOf(DirectAdvanceAssignment advanceAssignment) { if (advanceAssignment != null && isSubcontractedByCustomer()) { AdvanceMeasurement lastAdvanceMeasurementReported = null; for (AdvanceMeasurement advanceMeasurement : advanceAssignment.getAdvanceMeasurements()) { if (advanceMeasurement.getCommunicationDate() != null) { if (lastAdvanceMeasurementReported == null) { lastAdvanceMeasurementReported = advanceMeasurement; } else { if (advanceMeasurement.getCommunicationDate() .compareTo(lastAdvanceMeasurementReported.getCommunicationDate()) > 0) { lastAdvanceMeasurementReported = advanceMeasurement; } } } } return (lastAdvanceMeasurementReported != null) ? lastAdvanceMeasurementReported.getDate() : null; } return null; } private Boolean isSubcontractedByCustomer() { if (orderElement != null) { Order order = orderElement.getOrder(); if (order != null && order.getExternalCode() != null) { return true; } } return false; } @Override public boolean hasReportedProgress(AdvanceAssignment advance) { return advance instanceof DirectAdvanceAssignment && isSubcontractedByCustomer() && isSubcontractedAdvanceType(advance) && (getLastReportedProgressToCustomerOf((DirectAdvanceAssignment) advance) != null); } }