diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementHandler.java index b6eba3bc9..c0f561acf 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementHandler.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementHandler.java @@ -20,141 +20,154 @@ package org.navalplanner.business.orders.entities; +import static org.navalplanner.business.i18n.I18nHelper._; + +import java.util.Collection; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Set; +import org.hibernate.sql.Template; import org.navalplanner.business.requirements.entities.CriterionRequirement; import org.navalplanner.business.requirements.entities.DirectCriterionRequirement; import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.ResourceEnum; +import org.navalplanner.business.templates.entities.OrderElementTemplate; /** * @author Susana Montes Pedreira + * @author Diego Pino Garcia */ -public class CriterionRequirementHandler implements + +// +public abstract class CriterionRequirementHandler implements ICriterionRequirementHandler { - private static final CriterionRequirementHandler singleton = new CriterionRequirementHandler(); - - private CriterionRequirementHandler() { - - } - - public static CriterionRequirementHandler getInstance() { - return singleton; - } - // Operations to add a criterionRequirement - public void propagateDirectCriterionRequirementAddition( - OrderElement orderElement, CriterionRequirement directo) { + public void propagateDirectCriterionRequirementAddition(T orderElement, + CriterionRequirement directo) { propagateIndirectCriterionRequirement(orderElement, (DirectCriterionRequirement) directo); } - private void propagateIndirectCriterionRequirement( - OrderElement orderElement, - CriterionRequirement directo) { - if (orderElement instanceof OrderLine) { - propagateIndirectCriterionRequirementToChildren( - (OrderLine) orderElement, - (DirectCriterionRequirement) directo); + protected void propagateIndirectCriterionRequirement(T orderElement, + CriterionRequirement direct) { + + if (isOrderLine(orderElement)) { + propagateIndirectCriterionRequirementToOrderLineChildren( + toOrderLine(orderElement), + (DirectCriterionRequirement) direct); } else { - propagateIndirectCriterionRequirementToChildren( - (OrderLineGroup) orderElement, - (DirectCriterionRequirement) directo); + propagateIndirectCriterionRequirementToOrderLineGroupChildren( + toOrderLineGroup(orderElement), + (DirectCriterionRequirement) direct); } } - void propagateIndirectCriterionRequirementToChildren( - OrderLineGroup orderLineGroup, DirectCriterionRequirement parent) { + protected void propagateIndirectCriterionRequirementToOrderLineGroupChildren( + R orderLineGroup, DirectCriterionRequirement parent) { Criterion criterion = parent.getCriterion(); - for (OrderElement child : orderLineGroup.getChildren()) { + for (T child : getOrderLineGroupChildren(orderLineGroup)) { IndirectCriterionRequirement indirect = IndirectCriterionRequirement .create(parent, criterion); - child.addIndirectCriterionRequirement(indirect); + addIndirectCriterionRequirement(child, indirect); propagateIndirectCriterionRequirement(child, parent); } } - void propagateIndirectCriterionRequirementToChildren(OrderLine orderLine, - DirectCriterionRequirement parent) { - Criterion criterion = parent.getCriterion(); - for (HoursGroup hoursGroup : orderLine.getHoursGroups()) { + protected void propagateIndirectCriterionRequirementToOrderLineChildren( + S orderLine, DirectCriterionRequirement parent) { + for (HoursGroup hoursGroup : getHoursGroups(orderLine)) { hoursGroup.updateMyCriterionRequirements(); } } - boolean canAddCriterionRequirement(OrderElement orderElement, + protected abstract boolean isOrderLine(T orderElement); + + protected abstract S toOrderLine(T orderElement); + + protected abstract R toOrderLineGroup(T orderElement); + + protected abstract List getHoursGroups(S orderline); + + protected abstract List getOrderLineGroupChildren(R orderLineGroup); + + public boolean canAddCriterionRequirement(T orderElement, CriterionRequirement newRequirement) { - List listOrderElements = orderElement.getAllChildren(); + List listOrderElements = getAllChildren(orderElement); listOrderElements.add(orderElement); - for (OrderElement element : listOrderElements) { + for (T element : listOrderElements) { if (existSameCriterionRequirement(element, newRequirement)) return false; } return true; } - private boolean existSameCriterionRequirement(OrderElement orderElement, - CriterionRequirement newRequirement){ - if (orderElement instanceof OrderLine) { - return existSameCriterionRequirementIntoOrderLine( - (OrderLine) orderElement,newRequirement); + protected abstract List getAllChildren(T orderElement); + + public boolean existSameCriterionRequirement(T orderElement, + CriterionRequirement newRequirement) { + if (isOrderLine(orderElement)) { + return existSameCriterionRequirementIntoOrderLine(toOrderLine(orderElement), newRequirement); } else { - return existSameCriterionRequirementIntoOrderElement( - (OrderLineGroup) orderElement, newRequirement); + return existSameCriterionRequirementIntoOrderElement(orderElement, + newRequirement); } } - private boolean existSameCriterionRequirementIntoOrderElement( - OrderElement orderElement, + public boolean existSameCriterionRequirementIntoOrderLine(S orderLine, CriterionRequirement newRequirement) { - Criterion criterion = newRequirement.getCriterion(); - for (CriterionRequirement requirement : orderElement - .getCriterionRequirements()) { - if (requirement.getCriterion().equals(criterion)) - return true; - } - return false; - } - - boolean existSameCriterionRequirementIntoOrderLine(OrderLine orderLine, - CriterionRequirement newRequirement) { - if (existSameCriterionRequirementIntoOrderElement(orderLine, + if (existSameCriterionRequirementIntoOrderElement(toOrderElement(orderLine), newRequirement)) { return true; } - for (HoursGroup hoursGroup : orderLine.getHoursGroups()) { + for (HoursGroup hoursGroup : getHoursGroups(orderLine)) { if (hoursGroup.existSameCriterionRequirement(newRequirement)) return true; } return false; } + protected abstract T toOrderElement(S orderLine); + + public boolean existSameCriterionRequirementIntoOrderElement( + T orderElement, CriterionRequirement newRequirement) { + Criterion criterion = newRequirement.getCriterion(); + for (CriterionRequirement requirement : getCriterionRequirements(orderElement)) { + if (requirement.getCriterion().equals(criterion)) + return true; + } + return false; + } + + protected abstract Set getCriterionRequirements( + T orderElement); + /* * Operations to set the valid value of a criterion Requirements and the * criterion Requirement of its children. */ - public void propagateValidCriterionRequirement(OrderElement orderElement, + public void propagateValidCriterionRequirement(T orderElement, DirectCriterionRequirement parent, boolean valid) { - if (orderElement instanceof OrderLine) { - setValidCriterionRequirementChildren((OrderLine) orderElement, - parent, valid); + if (isOrderLine(orderElement)) { + setValidCriterionRequirementChildrenAsOrderLine( + toOrderLine(orderElement), parent, valid); } else { - setValidCriterionRequirementChildren((OrderLineGroup) orderElement, - parent, valid); + setValidCriterionRequirementChildrenAsOrderLineGroup( + toOrderLineGroup(orderElement), parent, valid); } } - protected void setValidCriterionRequirementChildren( - OrderLineGroup orderLineGroup, - DirectCriterionRequirement parent, boolean valid) { - for (OrderElement child : orderLineGroup.getChildren()) { + protected void setValidCriterionRequirementChildrenAsOrderLineGroup( + R orderLineGroup, DirectCriterionRequirement parent, + boolean valid) { + for (T child : getOrderLineGroupChildren(orderLineGroup)) { IndirectCriterionRequirement indirect = findIndirectRequirementByParent( - child.getIndirectCriterionRequirement(), parent); + getIndirectCriterionRequirement(child), parent); if (indirect != null) { indirect.setValid(valid); } @@ -162,9 +175,12 @@ public class CriterionRequirementHandler implements } } - protected void setValidCriterionRequirementChildren(OrderLine orderLine, + protected abstract Set getIndirectCriterionRequirement( + T orderElement); + + protected void setValidCriterionRequirementChildrenAsOrderLine(S orderLine, DirectCriterionRequirement parent, boolean valid) { - for (HoursGroup hoursGroup : orderLine.getHoursGroups()) { + for (HoursGroup hoursGroup : getHoursGroups(orderLine)) { IndirectCriterionRequirement indirect = findIndirectRequirementByParent( hoursGroup.getIndirectCriterionRequirement(), parent); if (indirect != null) { @@ -177,31 +193,34 @@ public class CriterionRequirementHandler implements * Operation to update the criterions requirements of the orderElement and * its children */ - public void propagateRemoveCriterionRequirement(OrderElement orderElement, + public void propagateRemoveCriterionRequirement(T orderElement, DirectCriterionRequirement parent) { - if (orderElement instanceof OrderLine) { - removeIndirectCriterionRequirement((OrderLine) orderElement, parent); + if (isOrderLine(orderElement)) { + removeIndirectCriterionRequirementAsOrderLine(toOrderLine(orderElement), parent); } else { - removeIndirectCriterionRequirement((OrderLineGroup) orderElement, + removeIndirectCriterionRequirement(toOrderLineGroup(orderElement), parent); } } protected void removeIndirectCriterionRequirement( - OrderLineGroup orderLineGroup, DirectCriterionRequirement parent) { - for (OrderElement child : orderLineGroup.getChildren()) { + R orderLineGroup, DirectCriterionRequirement parent) { + for (T child : getOrderLineGroupChildren(orderLineGroup)) { IndirectCriterionRequirement indirect = findIndirectRequirementByParent( - child.getIndirectCriterionRequirement(), parent); + getIndirectCriterionRequirement(child), parent); if (indirect != null) { propagateRemoveCriterionRequirement(child, parent); - child.removeCriterionRequirement(indirect); + removeCriterionRequirement(child, indirect); } } } - protected void removeIndirectCriterionRequirement(OrderLine orderLine, + protected abstract void removeCriterionRequirement(T orderElement, + CriterionRequirement criterionRequirement); + + protected void removeIndirectCriterionRequirementAsOrderLine(S orderLine, DirectCriterionRequirement parent) { - for (HoursGroup hoursGroup : orderLine.getHoursGroups()) { + for (HoursGroup hoursGroup : getHoursGroups(orderLine)) { IndirectCriterionRequirement indirect = findIndirectRequirementByParent( hoursGroup.getIndirectCriterionRequirement(), parent); if (indirect != null) { @@ -210,62 +229,74 @@ public class CriterionRequirementHandler implements } } + public void removeDirectCriterionRequirement(T orderElement, DirectCriterionRequirement criterionRequirement){ + propagateRemoveCriterionRequirement(orderElement, criterionRequirement); + removeCriterionRequirement(orderElement, criterionRequirement); + } + + protected abstract List getOrderLineHoursGroups(S orderLine); + /* * Operation to update the criterions requirements of the orderElement and * its children */ - public void propagateUpdateCriterionRequirements(OrderElement orderElement) { + public void propagateUpdateCriterionRequirements(T orderElement) { if (orderElement instanceof OrderLine) { - updateCriterionRequirementsIntoOrderLine((OrderLine) orderElement); + updateCriterionRequirementsIntoOrderLine(toOrderLine(orderElement)); } else { - updateCriterionRequirementsIntoOrderLineGroup((OrderLineGroup) orderElement); + updateCriterionRequirementsIntoOrderLineGroup(toOrderLineGroup(orderElement)); } } private void updateCriterionRequirementsIntoOrderLineGroup( - OrderElement orderLineGroup) { - for (OrderElement child : orderLineGroup.getChildren()) { - child.updateMyCriterionRequirements(); + R orderLineGroup) { + for (T child : getOrderLineGroupChildren(orderLineGroup)) { + updateMyCriterionRequirements(child); propagateUpdateCriterionRequirements(child); } } - private void updateCriterionRequirementsIntoOrderLine(OrderLine orderLine) { - for (HoursGroup hoursGroup : orderLine.getHoursGroups()) { + protected abstract List getChildren(T orderElement); + + private void updateCriterionRequirementsIntoOrderLine(S orderLine) { + for (HoursGroup hoursGroup : getHoursGroups(orderLine)) { hoursGroup.updateMyCriterionRequirements(); } } - void transformDirectToIndirectIfNeeded(OrderElement orderElement, + void transformDirectToIndirectIfNeeded(T orderElement, Set currents) { - for (DirectCriterionRequirement direct : orderElement - .getDirectCriterionRequirement()) { + for (DirectCriterionRequirement direct : getDirectCriterionRequirement(orderElement)) { IndirectCriterionRequirement indirect = findIndirectRequirementByCriterion( currents, direct.getCriterion()); if (indirect != null) { - orderElement.removeDirectCriterionRequirement(direct); + removeDirectCriterionRequirement(orderElement, direct); } } } - void addNewsIndirects(OrderElement orderElement, + protected abstract Set getDirectCriterionRequirement( + T orderElement); + + void addNewsIndirects(T orderElement, Set currents) { - Set indirects = orderElement - .getIndirectCriterionRequirement(); + Set indirects = getIndirectCriterionRequirement(orderElement); for (IndirectCriterionRequirement current : currents) { if (!indirects.contains(current)) { - orderElement.basicAddCriterionRequirement(current); + basicAddCriterionRequirement(orderElement, current); } } } - void removeOldIndirects(OrderElement orderElement, + protected abstract void basicAddCriterionRequirement(T orderElement, + CriterionRequirement criterionRequirement); + + void removeOldIndirects(T orderElement, Set currents) { - for (IndirectCriterionRequirement indirect : orderElement - .getIndirectCriterionRequirement()) { + for (IndirectCriterionRequirement indirect : getIndirectCriterionRequirement(orderElement)) { if (!currents.contains(indirect)) { - orderElement.removeCriterionRequirement(indirect); + removeCriterionRequirement(orderElement, indirect); } } } @@ -341,6 +372,7 @@ public class CriterionRequirementHandler implements private IndirectCriterionRequirement findIndirectRequirementByParent( Set indirects, DirectCriterionRequirement newParent) { + for (IndirectCriterionRequirement requirement : indirects) { if (requirement.getParent().equals(newParent)) { return requirement; @@ -351,6 +383,7 @@ public class CriterionRequirementHandler implements private IndirectCriterionRequirement findIndirectRequirementByCriterion( Set indirects, Criterion criterion) { + for (IndirectCriterionRequirement requirement : indirects) { if (requirement.getCriterion().equals(criterion)) { return requirement; @@ -358,41 +391,57 @@ public class CriterionRequirementHandler implements } return null; } + /* * Operation to create and add to a orderElement new criterion requirements * that it is copied of the criterion requirements of other orderElement */ - protected void copyRequirementToOrderElement(OrderLine orderLine, - OrderLineGroup container) { + protected void copyRequirementToOrderLineGroup(S orderLine, R orderLineGroup) { // copy the directCriterionRequirement - for (DirectCriterionRequirement newRequirement : copyDirectRequirements(orderLine - .getDirectCriterionRequirement())) { - container.basicAddCriterionRequirement(newRequirement); + for (DirectCriterionRequirement newRequirement : + copyDirectRequirements(getDirectCriterionRequirementFromOrderLine(orderLine))) { + basicAddCriterionRequirementIntoOrderLineGroup(orderLineGroup, newRequirement); } + // copy the IndirectCriterionRequirement - for (IndirectCriterionRequirement newRequirement : copyIndirectRequirements(orderLine - .getIndirectCriterionRequirement())) { - container.basicAddCriterionRequirement(newRequirement); + for (IndirectCriterionRequirement newRequirement : + copyIndirectRequirements(getIndirectCriterionRequirementFromOrderLine(orderLine))) { + basicAddCriterionRequirementIntoOrderLineGroup(orderLineGroup, newRequirement); } } - protected void copyRequirementToOrderElement(OrderLineGroup orderLineGroup, - OrderLine leaf) { + protected abstract Set getDirectCriterionRequirementFromOrderLine(S orderLine); + + protected abstract Set getIndirectCriterionRequirementFromOrderLine(S orderLine); + + protected abstract void basicAddCriterionRequirementIntoOrderLineGroup( + R orderLineGroup, + CriterionRequirement criterionRequirement); + + protected void copyRequirementToOrderLine(R orderLineGroup, S orderLine) { // copy the directCriterionRequirement - for (DirectCriterionRequirement newRequirement : copyDirectRequirements(orderLineGroup - .getDirectCriterionRequirement())) { - leaf.addDirectCriterionRequirement(newRequirement); + for (DirectCriterionRequirement newRequirement : copyDirectRequirements( + getDirectCriterionRequirementFromOrderLineGroup(orderLineGroup))) { + addDirectCriterionRequirementToOrderLine(orderLine, newRequirement); } // copy the IndirectCriterionRequirement - for (IndirectCriterionRequirement newRequirement : copyIndirectRequirements(orderLineGroup - .getIndirectCriterionRequirement())) { - leaf.addIndirectCriterionRequirement(newRequirement); - propagateIndirectCriterionRequirementToChildren(leaf, + for (IndirectCriterionRequirement newRequirement : copyIndirectRequirements( + getIndirectCriterionRequirementFromOrderLineGroup(orderLineGroup))) { + addIndirectCriterionRequirementToOrderLine(orderLine, newRequirement); + propagateIndirectCriterionRequirementToOrderLineChildren(orderLine, newRequirement.getParent()); } } - private Set copyDirectRequirements(Set collection){ + protected abstract Set + getDirectCriterionRequirementFromOrderLineGroup(R orderLineGroup); + + protected abstract void addIndirectCriterionRequirementToOrderLine(S orderLine, IndirectCriterionRequirement indirect); + + protected abstract Set getIndirectCriterionRequirementFromOrderLineGroup(R orderLineGroup); + + private Set copyDirectRequirements( + Set collection) { Set result = new HashSet(); for (DirectCriterionRequirement requirement : collection) { DirectCriterionRequirement newRequirement = DirectCriterionRequirement @@ -415,8 +464,7 @@ public class CriterionRequirementHandler implements } Set getRequirementWithSameResourType( - Set requirements, - ResourceEnum resourceType) { + Set requirements, ResourceEnum resourceType) { Set result = new HashSet(); for (CriterionRequirement requirement : requirements) { ResourceEnum resourceTypeParent = requirement.getCriterion() @@ -427,4 +475,177 @@ public class CriterionRequirementHandler implements } return result; } -} \ No newline at end of file + + /** + * Filters {@link DirectCriterionRequirement} from criterionRequirements + * + * @param criterionRequirements + * @return + */ + public Set getDirectCriterionRequirement( + Set criterionRequirements) { + + Set list = new HashSet(); + + for (CriterionRequirement criterionRequirement : criterionRequirements) { + if (criterionRequirement instanceof DirectCriterionRequirement) { + list.add((DirectCriterionRequirement) criterionRequirement); + } + } + return list; + } + + public Set getIndirectCriterionRequirement( + Set criterionRequirements) { + + Set list = new HashSet(); + + for (CriterionRequirement criterionRequirement : criterionRequirements) { + if (criterionRequirement instanceof IndirectCriterionRequirement) { + list.add((IndirectCriterionRequirement) criterionRequirement); + } + } + return list; + } + + public void addCriterionRequirement(T orderElement, + CriterionRequirement criterionRequirement) { + if (criterionRequirement instanceof DirectCriterionRequirement) { + addDirectCriterionRequirement(orderElement, (DirectCriterionRequirement) criterionRequirement); + } else { // criterionRequirement instanceof IndirectCriterionRequirement + addIndirectCriterionRequirement(orderElement, (IndirectCriterionRequirement) criterionRequirement); + } + } + + public void addDirectCriterionRequirement(T orderElement, + CriterionRequirement newRequirement) { + if (canAddCriterionRequirement(orderElement, + newRequirement)) { + basicAddCriterionRequirement(orderElement, newRequirement); + propagateDirectCriterionRequirementAddition(orderElement, + newRequirement); + } else { + final Criterion criterion = newRequirement.getCriterion(); + throw new IllegalStateException(_( + " The {0} already exist into other order element", + criterion.getName())); + } + } + + public void addIndirectCriterionRequirement(T orderElement, + IndirectCriterionRequirement criterionRequirement) { + basicAddCriterionRequirement(orderElement, criterionRequirement); + } + + protected void addDirectCriterionRequirementToOrderLine(S orderLine, DirectCriterionRequirement direct) { + addDirectCriterionRequirement(toOrderElement(orderLine), direct); + } + + public void updateMyCriterionRequirements(T orderElement) { + final T parent = getParent(orderElement); + + Set requirementsParent = getCriterionRequirements(parent); + Set currentIndirects = getCurrentIndirectRequirements( + getIndirectCriterionRequirement(orderElement), + requirementsParent); + transformDirectToIndirectIfNeeded(orderElement, currentIndirects); + removeOldIndirects(orderElement, currentIndirects); + addNewsIndirects(orderElement, currentIndirects); + } + + protected abstract T getParent(T orderElement); + + /** + * Propagates {@link IndirectCriterionRequirement} for an + * {@link OrderElement} or {@link OrderElementTemplate} preserving its valid + * attribute + * + */ + public void copyIndirectCriterionRequirementFromOriginalToOrderLineGroupChildren( + R orderLineGroup, + DirectCriterionRequirement parent) { + + copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + orderLineGroup, parent); + copyIndirectCriterionRequirementsFromOriginalToHoursGroup( + orderLineGroup, parent); + } + + public abstract void copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + R orderLineGroup, + DirectCriterionRequirement parent); + + public void copyIndirectCriterionRequirementsFromOriginalToHoursGroup( + R orderLineGroup, + DirectCriterionRequirement parent) { + + final List orderElements = getOrderLineGroupChildren(orderLineGroup); + final Criterion criterion = parent.getCriterion(); + final Set originalIndirectCriterionRequirements = parent + .getOrigin().getChildren(); + final Map> mapHoursGroup = + createHoursGroupCriterionMap(originalIndirectCriterionRequirements); + + for (T each: orderElements) { + + IndirectCriterionRequirement indirect = IndirectCriterionRequirement + .create(parent, criterion); + + if (isOrderLine(each)) { + for (HoursGroup hoursGroup: myHoursGroups(toOrderLine(each))) { + Map criterionMap = mapHoursGroup.get(hoursGroup.getOrigin()); + if (criterionMap != null) { + final Boolean valid = criterionMap.get(indirect.getCriterion()); + indirect.setValid(valid); + } + hoursGroup.addCriterionRequirement(indirect); + } + } + + if (isOrderLineGroup(each)) { + copyIndirectCriterionRequirementsFromOriginalToHoursGroup( + toOrderLineGroup(each), parent); + } + + } + } + + protected abstract boolean isOrderLineGroup(T orderElement); + + protected abstract Collection myHoursGroups(S orderline); + + /** + * Creates a mapping between {@link HoursGroup} and a tuple (criterion, + * boolean) from a list of {@link IndirectCriterionRequirement} + * + * The valid value of an {@link IndirectCriterionRequirement} can be later + * retrieve knowing its {@link HoursGroup} and its {@link Criterion} + * + * This data structure is used to keep the original valid value from + * {@link IndirectCriterionRequirement} when copying an {@link Order} to a + * {@link Template} or vice-versa + * + * @param indirects + * @return + */ + private Map> createHoursGroupCriterionMap( + Set indirects) { + + Map> result = + new HashMap>(); + + for (IndirectCriterionRequirement each: indirects) { + final HoursGroup hoursGroup = each.getHoursGroup(); + if (hoursGroup != null) { + Map value = result.get(hoursGroup); + if (value == null) { + value = new HashMap(); + } + value.put(each.getCriterion(), each.isValid()); + result.put(hoursGroup, value); + } + } + return result; + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementOrderElementHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementOrderElementHandler.java new file mode 100644 index 000000000..beb13f9cc --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/CriterionRequirementOrderElementHandler.java @@ -0,0 +1,243 @@ +/* + * This file is part of ###PROJECT_NAME### + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.orders.entities; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.navalplanner.business.requirements.entities.CriterionRequirement; +import org.navalplanner.business.requirements.entities.DirectCriterionRequirement; +import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; +import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.templates.entities.OrderElementTemplate; + +/** + * + * @author Diego Pino Garcia + * + */ +public class CriterionRequirementOrderElementHandler extends + CriterionRequirementHandler { + + private static final CriterionRequirementOrderElementHandler singleton = + new CriterionRequirementOrderElementHandler(); + + private CriterionRequirementOrderElementHandler() { + + } + + public static CriterionRequirementOrderElementHandler getInstance() { + return singleton; + } + + @Override + protected List getOrderLineGroupChildren(OrderLineGroup orderLineGroup) { + return orderLineGroup.getChildren(); + } + + @Override + protected List getAllChildren(OrderElement orderElement) { + return orderElement.getAllChildren(); + } + + @Override + protected List getChildren(OrderElement orderElement) { + return orderElement.getChildren(); + } + + @Override + protected Set getCriterionRequirements(OrderElement orderElement) { + return orderElement.getCriterionRequirements(); + } + + @Override + protected Set getIndirectCriterionRequirement(OrderElement orderElement) { + return orderElement.getIndirectCriterionRequirement(); + } + + @Override + protected void removeCriterionRequirement(OrderElement orderElement, + CriterionRequirement criterionRequirement) { + orderElement.removeCriterionRequirement(criterionRequirement); + } + + @Override + protected List getOrderLineHoursGroups(OrderLine orderLine) { + return orderLine.getHoursGroups(); + } + + @Override + protected Set getDirectCriterionRequirement(OrderElement orderElement) { + return orderElement.getDirectCriterionRequirement(); + } + + @Override + protected void basicAddCriterionRequirement(OrderElement orderElement, CriterionRequirement criterionRequirement) { + orderElement.basicAddCriterionRequirement(criterionRequirement); + } + + @Override + protected List getHoursGroups(OrderLine orderline) { + return orderline.getHoursGroups(); + } + + @Override + protected boolean isOrderLine(OrderElement orderElement) { + return (orderElement instanceof OrderLine); + } + + @Override + protected OrderLine toOrderLine(OrderElement orderElement) { + return (OrderLine) orderElement; + } + + @Override + protected OrderLineGroup toOrderLineGroup(OrderElement orderElement) { + return (OrderLineGroup) orderElement; + } + + @Override + protected OrderElement toOrderElement(OrderLine orderLine) { + return (OrderElement) orderLine; + } + + @Override + protected Set + getDirectCriterionRequirementFromOrderLineGroup(OrderLineGroup orderLineGroup) { + return orderLineGroup.getDirectCriterionRequirement(); + } + + @Override + protected void addIndirectCriterionRequirementToOrderLine(OrderLine orderLine, IndirectCriterionRequirement indirect) { + orderLine.addIndirectCriterionRequirement(indirect); + } + + @Override + protected Set getIndirectCriterionRequirementFromOrderLineGroup( + OrderLineGroup orderLine) { + return orderLine.getIndirectCriterionRequirement(); + } + + @Override + protected Set getDirectCriterionRequirementFromOrderLine(OrderLine orderLine) { + return orderLine.getDirectCriterionRequirement(); + } + + @Override + protected Set getIndirectCriterionRequirementFromOrderLine(OrderLine orderLine) { + return orderLine.getIndirectCriterionRequirement(); + } + + @Override + protected void basicAddCriterionRequirementIntoOrderLineGroup(OrderLineGroup orderLineGroup, CriterionRequirement criterionRequirement) { + orderLineGroup.basicAddCriterionRequirement(criterionRequirement); + } + + @Override + protected OrderElement getParent(OrderElement orderElement) { + return orderElement.getParent(); + } + + @Override + protected boolean isOrderLineGroup(OrderElement orderElement) { + return (orderElement instanceof OrderLineGroup); + } + + @Override + protected Collection myHoursGroups(OrderLine orderline) { + return orderline.myHoursGroups(); + } + + /** + * For every OrderLineGroup, its {@link DirectCriterionRequirement} are + * copied to their children ({@link IndirectCriterionRequirement}). Every entry of + * {@link DirectCriterionRequirement} keeps a reference to its original + * (_origin_). Original {@link IndirectCriterionRequirement} can be accessed + * from _origin_. + * + * A unique IndirectCriterionRequirements can be referenced knowing two + * parameters: {@link OrderElement} or {@link OrderElementTemplate}, and + * {@link Criterion}. A map containing the original valid value of an + * indirect criterion is created, indexing by order element and criterion. + * + * Every order element keeps a reference to its template, and vice-versa. So + * when propagating a criterion it's possible to know the original value of + * valid via the map previously created + */ + @Override + public void copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + OrderLineGroup orderLineGroup, DirectCriterionRequirement parent) { + + final List orderElements = orderLineGroup.getChildren(); + final Criterion criterion = parent.getCriterion(); + final Set originalIndirectCriterionRequirements = parent + .getOrigin().getChildren(); + final Map> mapTemplateCriterion = + createTemplateCriterionMap(originalIndirectCriterionRequirements); + + for (OrderElement each : orderElements) { + Map criterionMap = mapTemplateCriterion + .get(each.getTemplate()); + if (criterionMap != null) { + IndirectCriterionRequirement indirect = IndirectCriterionRequirement + .create(parent, criterion); + indirect.setValid(criterionMap.get(criterion)); + addIndirectCriterionRequirement(each, indirect); + } + + if (isOrderLineGroup(each)) { + copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + toOrderLineGroup(each), parent); + } + } + } + + /** + * Map containing {@link IndirectCriterionRequirement} valid attribute, + * indexing by {@link OrderElementTemplate} and {@link Criterion} + * + * @param indirects + * @return + */ + private Map> createTemplateCriterionMap( + Set indirects) { + + Map> result = + new HashMap>(); + + for (IndirectCriterionRequirement each: indirects) { + final OrderElementTemplate template = each.getOrderElementTemplate(); + if (template != null) { + Map value = result.get(template); + if (value == null) { + value = new HashMap(); + } + value.put(each.getCriterion(), each.isValid()); + result.put(template, value); + } + } + return result; + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroup.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroup.java index 68fba0866..89301b540 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroup.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroup.java @@ -22,9 +22,11 @@ package org.navalplanner.business.orders.entities; import static org.navalplanner.business.i18n.I18nHelper._; import java.math.BigDecimal; +import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.UUID; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -41,27 +43,13 @@ import org.navalplanner.business.requirements.entities.DirectCriterionRequiremen import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.ResourceEnum; +import org.navalplanner.business.templates.entities.OrderLineTemplate; public class HoursGroup extends BaseEntity implements Cloneable, ICriterionRequirable { private static final Log LOG = LogFactory.getLog(HoursGroup.class); - public static HoursGroup create(OrderLine parentOrderLine) { - HoursGroup result = new HoursGroup(parentOrderLine); - result.setNewObject(true); - return result; - } - - public static HoursGroup createUnvalidated(String name, - ResourceEnum resourceType, Integer workingHours) { - HoursGroup result = new HoursGroup(); - result.setCode(name); - result.setResourceType(resourceType); - result.setWorkingHours(workingHours); - return create(result); - } - private String code; private ResourceEnum resourceType = ResourceEnum.WORKER; @@ -74,20 +62,105 @@ public class HoursGroup extends BaseEntity implements Cloneable, private Set criterionRequirements = new HashSet(); - @NotNull private OrderLine parentOrderLine; - protected CriterionRequirementHandler criterionRequirementHandler = CriterionRequirementHandler - .getInstance(); + private OrderLineTemplate orderLineTemplate; + + private HoursGroup origin; + + protected CriterionRequirementOrderElementHandler criterionRequirementHandler = + CriterionRequirementOrderElementHandler.getInstance(); + + + public static HoursGroup create(OrderLine parentOrderLine) { + HoursGroup result = new HoursGroup(parentOrderLine); + result.setNewObject(true); + return result; + } + + public static HoursGroup create(OrderLineTemplate orderLineTemplate) { + HoursGroup result = new HoursGroup(orderLineTemplate); + result.setNewObject(true); + return result; + } + + public static HoursGroup createUnvalidated(String code, + ResourceEnum resourceType, Integer workingHours) { + HoursGroup result = new HoursGroup(); + result.setCode(code); + result.setResourceType(resourceType); + result.setWorkingHours(workingHours); + return create(result); + } + + /** + * Returns a copy of hoursGroup, and sets parent as its parent + * + * @param hoursGroup + * @param parent + * @return + */ + public static HoursGroup copyFrom(HoursGroup hoursGroup, OrderLineTemplate parent) { + HoursGroup result = copyFrom(hoursGroup); + result.setCriterionRequirements(copyDirectCriterionRequirements( + result, parent, hoursGroup.getDirectCriterionRequirement())); + result.setOrderLineTemplate(parent); + result.setParentOrderLine(null); + return result; + } + + private static Set copyDirectCriterionRequirements( + HoursGroup hoursGroup, + Object orderLine, + Collection criterionRequirements) { + Set result = new HashSet(); + + for (DirectCriterionRequirement each: criterionRequirements) { + final DirectCriterionRequirement directCriterionRequirement = (DirectCriterionRequirement) each; + DirectCriterionRequirement newDirectCriterionRequirement = DirectCriterionRequirement + .copyFrom(directCriterionRequirement, hoursGroup); + newDirectCriterionRequirement.setHoursGroup(hoursGroup); + result.add(newDirectCriterionRequirement); + } + return result; + } + + public static HoursGroup copyFrom(HoursGroup hoursGroup, OrderLine parent) { + HoursGroup result = copyFrom(hoursGroup); + result.setCriterionRequirements(copyDirectCriterionRequirements( + result, parent, hoursGroup.getDirectCriterionRequirement())); + result.setOrderLineTemplate(null); + result.setParentOrderLine(parent); + return result; + } + + private static HoursGroup copyFrom(HoursGroup hoursGroup) { + HoursGroup result = createUnvalidated( + hoursGroup.getCode(), + hoursGroup.getResourceType(), + hoursGroup.getWorkingHours()); + result.setCode(UUID.randomUUID().toString()); + result.percentage = hoursGroup.getPercentage(); + result.fixedPercentage = hoursGroup.isFixedPercentage(); + result.origin = hoursGroup; + return result; + } /** * Constructor for hibernate. Do not use! */ public HoursGroup() { + } private HoursGroup(OrderLine parentOrderLine) { this.parentOrderLine = parentOrderLine; + this.setOrderLineTemplate(null); + } + + private HoursGroup(OrderLineTemplate orderLineTemplate) { + this.orderLineTemplate = orderLineTemplate; + this.setParentOrderLine(null); } @NotEmpty(message = "code not specified") @@ -139,13 +212,18 @@ public class HoursGroup extends BaseEntity implements Cloneable, this.percentage = proportion; - if (!parentOrderLine.isPercentageValid()) { + if (!isPercentageValidForParent()) { this.percentage = oldPercentage; throw new IllegalArgumentException( _("Total percentage should be less than 100%")); } } + private boolean isPercentageValidForParent() { + return (parentOrderLine != null) ? parentOrderLine.isPercentageValid() + : orderLineTemplate.isPercentageValid(); + } + public BigDecimal getPercentage() { return percentage; } @@ -231,10 +309,9 @@ public class HoursGroup extends BaseEntity implements Cloneable, } public void updateMyCriterionRequirements() { - OrderElement newParent = this.getParentOrderLine(); Set requirementsParent = criterionRequirementHandler - .getRequirementWithSameResourType(newParent - .getCriterionRequirements(), resourceType); + .getRequirementWithSameResourType( + getCriterionRequirementsFromParent(), resourceType); Set currentIndirects = criterionRequirementHandler .getCurrentIndirectRequirements( getIndirectCriterionRequirement(), requirementsParent); @@ -242,6 +319,12 @@ public class HoursGroup extends BaseEntity implements Cloneable, criterionRequirementHandler.addNewsIndirects(this, currentIndirects); } + private Set getCriterionRequirementsFromParent() { + return (parentOrderLine != null) ? parentOrderLine + .getCriterionRequirements() : orderLineTemplate + .getCriterionRequirements(); + } + public Set getIndirectCriterionRequirement() { Set list = new HashSet(); for(CriterionRequirement criterionRequirement : criterionRequirements ){ @@ -304,4 +387,20 @@ public class HoursGroup extends BaseEntity implements Cloneable, } } + public OrderLineTemplate getOrderLineTemplate() { + return orderLineTemplate; + } + + public void setOrderLineTemplate(OrderLineTemplate orderLineTemplate) { + this.orderLineTemplate = orderLineTemplate; + } + + public HoursGroup getOrigin() { + return origin; + } + + public void setOrigin(HoursGroup origin) { + this.origin = origin; + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupHandler.java new file mode 100644 index 000000000..b3efcb27e --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupHandler.java @@ -0,0 +1,284 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.orders.entities; + +import static org.navalplanner.business.i18n.I18nHelper._; + +import java.math.BigDecimal; +import java.util.HashSet; +import java.util.Set; + +/** + * + * @author Susana Montes Pedreira + * @author Diego Pino Garcia + */ +public abstract class HoursGroupHandler implements IHoursGroupHandler { + + public boolean isTotalHoursValid(Integer total, final Set hoursGroups) { + + if (total == null) { + return false; + } + + Integer newTotal = 0; + + for (HoursGroup hoursGroup : hoursGroups) { + if (hoursGroup.isFixedPercentage()) { + newTotal += hoursGroup.getPercentage().multiply( + new BigDecimal(total).setScale(2)).toBigInteger() + .intValue(); + } + } + + if (newTotal.compareTo(total) > 0) { + return false; + } + + return true; + } + + public boolean isPercentageValid(final Set hoursGroups) { + + BigDecimal newPercentage = new BigDecimal(0).setScale(2); + + for (HoursGroup hoursGroup : hoursGroups) { + if (hoursGroup.isFixedPercentage()) { + newPercentage = newPercentage.add(hoursGroup.getPercentage()); + } + } + + if (newPercentage.compareTo(new BigDecimal(1).setScale(2)) > 0) { + return false; + } + + return true; + } + + public Integer calculateTotalHours(Set hoursGroups) { + Integer result = 0; + for (HoursGroup hoursGroup : hoursGroups) { + Integer workingHours = hoursGroup.getWorkingHours(); + if (workingHours != null) { + result += workingHours; + } + } + return result; + } + + /** + * Calculates the total number of working hours in a set of + * {@link HoursGroup} taking into account just {@link HoursGroup} with + * NO_FIXED as policy. + * @param hoursGroups + * A {@link HoursGroup} set + * @return The sum of NO_FIXED {@link HoursGroup} + */ + private Integer calculateTotalHoursNoFixed(Set hoursGroups) { + Integer result = 0; + for (HoursGroup hoursGroup : hoursGroups) { + if (!hoursGroup.isFixedPercentage()) { + result += hoursGroup.getWorkingHours(); + } + } + return result; + } + + public void recalculateHoursGroups(T orderLine) { + Set hoursGroups = getHoursGroup(orderLine); + Integer total = calculateTotalHours(hoursGroups); + BigDecimal totalBigDecimal = new BigDecimal(total).setScale(2); + + // For each HoursGroup with FIXED_PERCENTAGE, the workingHours are + // calculated + for (HoursGroup hoursGroup : hoursGroups) { + if (hoursGroup.isFixedPercentage()) { + Integer workingHours = hoursGroup.getPercentage().multiply( + totalBigDecimal).toBigInteger().intValue(); + + hoursGroup.setWorkingHours(workingHours); + } + } + + Integer newTotal = calculateTotalHours(hoursGroups); + // If the total was modified + if (!newTotal.equals(total)) { + Integer totalNoFixed = calculateTotalHoursNoFixed(hoursGroups); + + // For each HoursGroup without FIXED_PERCENTAGE, the hours are + // proportionally shared + for (HoursGroup hoursGroup : hoursGroups) { + if (!hoursGroup.isFixedPercentage()) { + Integer hours = hoursGroup.getWorkingHours(); + Integer newHours = (int) (((float) hours / totalNoFixed) * (total - (newTotal - totalNoFixed))); + hoursGroup.setWorkingHours(newHours); + } + } + } + + newTotal = calculateTotalHours(hoursGroups); + // If there's still some remaining hours + if (newTotal.compareTo(total) < 0) { + // Add a new HourGroup with the remaining hours + HoursGroup hoursGroup = createHoursGroup(orderLine); + hoursGroup.updateMyCriterionRequirements(); + hoursGroup.setWorkingHours(total - newTotal); + hoursGroups.add(hoursGroup); + } + + // Then the percentages for the HoursGroup without FIXED_PERCENTAGE are + // recalculated. + for (HoursGroup hoursGroup : hoursGroups) { + if (!hoursGroup.isFixedPercentage()) { + if (totalBigDecimal.equals(new BigDecimal(0).setScale(2))) { + hoursGroup.setPercentage(new BigDecimal(0).setScale(2)); + } else { + BigDecimal hoursBigDecimal = new BigDecimal(hoursGroup + .getWorkingHours()).setScale(2); + BigDecimal percentage = hoursBigDecimal.divide( + totalBigDecimal, BigDecimal.ROUND_DOWN); + hoursGroup.setPercentage(percentage); + } + } + } + } + + protected abstract Set getHoursGroup(T orderLine); + + protected abstract HoursGroup createHoursGroup(T orderLine); + + private void updateHoursGroups(T orderLine, Integer workHours) { + final Set hoursGroups = getHoursGroup(orderLine); + Set newHoursGroups = new HashSet(); + + // Divide HourGroup depending on policy + Set fixedPercentageGroups = new HashSet(); + Set noFixedGroups = new HashSet(); + + for (HoursGroup hoursGroup : hoursGroups) { + if (hoursGroup.isFixedPercentage()) { + fixedPercentageGroups.add(hoursGroup); + } else { + noFixedGroups.add(hoursGroup); + } + } + + // For every HourGroup with FIXED_PERCENTAGE, workingHours will be + // calculated + for (HoursGroup hoursGroup : fixedPercentageGroups) { + Integer hours = hoursGroup.getPercentage().multiply( + new BigDecimal(workHours).setScale(2)).toBigInteger() + .intValue(); + hoursGroup.setWorkingHours(hours); + newHoursGroups.add(hoursGroup); + } + + Integer newTotal = calculateTotalHours(newHoursGroups); + + if (newTotal.compareTo(workHours) > 0) { + throw new RuntimeException("Unreachable code"); + } else if (newTotal.compareTo(workHours) == 0) { + for (HoursGroup hoursGroup : noFixedGroups) { + hoursGroup.setWorkingHours(0); + newHoursGroups.add(hoursGroup); + } + } else if (newTotal.compareTo(workHours) < 0) { + // Proportional sharing + Integer oldNoFixed = calculateTotalHoursNoFixed(hoursGroups); + Integer newNoFixed = workHours - newTotal; + + for (HoursGroup hoursGroup : noFixedGroups) { + Integer newHours; + if (oldNoFixed == 0) { + newHours = (int) ((float) newNoFixed / hoursGroups.size()); + } else { + newHours = (int) ((float) hoursGroup.getWorkingHours() + / oldNoFixed * newNoFixed); + } + hoursGroup.setWorkingHours(newHours); + + newHoursGroups.add(hoursGroup); + } + } + + // If there're remaining hours + newTotal = calculateTotalHours(newHoursGroups); + if (newTotal.compareTo(workHours) < 0) { + // Add a new HourGroup with the remaining hours + HoursGroup hoursGroup = createHoursGroup(orderLine); + hoursGroup.setWorkingHours(workHours - newTotal); + + newHoursGroups.add(hoursGroup); + } + + // Set the attribute with the new hours group calculated + setHoursGroups(orderLine, newHoursGroups); + + // Re-calculate percentages + recalculateHoursGroups(orderLine); + } + + protected abstract void setHoursGroups(T orderLine, Set hoursGroups); + + /** + * Set the total working hours of the {@link OrderLine} taking into account + * the {@link HoursGroup} policies. + * @param workHours + * The desired value to set as total working hours + * @throws IllegalArgumentException + * If parameter is less than 0 or if it's not possible to set + * this value taking into account {@link HoursGroup} policies. + */ + @Override + public void setWorkHours(T orderLine, Integer workHours) throws IllegalArgumentException { + + if (workHours == null) { + workHours = new Integer(0); + } + + if (workHours < 0) { + throw new IllegalArgumentException( + _("workHours should be greater or equals to 0")); + } + + if (hoursGroupsIsEmpty(orderLine)) { + HoursGroup hoursGroup = createHoursGroup(orderLine); + hoursGroup.setWorkingHours(workHours); + hoursGroup.setPercentage((new BigDecimal(1).setScale(2))); + hoursGroup.setCode(OrderLine.INITIAL_HOURS_GROUP_CODE); + addHoursGroup(orderLine, hoursGroup); + } else { + + if (!isTotalHoursValid(workHours, getHoursGroup(orderLine))) { + throw new IllegalArgumentException( + _("\"workHours\" value is not valid, taking into " + + "account the current list of HoursGroup")); + } + + updateHoursGroups(orderLine, workHours); + } + } + + protected abstract boolean hoursGroupsIsEmpty(T orderLine); + + protected abstract void addHoursGroup(T orderLine, HoursGroup hoursGroup); + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupOrderLineHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupOrderLineHandler.java new file mode 100644 index 000000000..26ed19cdf --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/HoursGroupOrderLineHandler.java @@ -0,0 +1,68 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.orders.entities; + +import java.util.Set; + +/** + * + * @author Diego Pino Garcia + */ +public class HoursGroupOrderLineHandler extends HoursGroupHandler { + + private static final HoursGroupOrderLineHandler singleton = + new HoursGroupOrderLineHandler(); + + private HoursGroupOrderLineHandler() { + + } + + public static HoursGroupOrderLineHandler getInstance() { + return singleton; + } + + @Override + protected HoursGroup createHoursGroup(OrderLine orderLine) { + return HoursGroup.create(orderLine); + } + + @Override + protected Set getHoursGroup(OrderLine orderLine) { + return orderLine.myHoursGroups(); + } + + @Override + protected void setHoursGroups(OrderLine orderLine, + Set hoursGroups) { + orderLine.setHoursGroups(hoursGroups); + } + + @Override + protected void addHoursGroup(OrderLine orderLine, HoursGroup hoursGroup) { + orderLine.doAddHoursGroup(hoursGroup); + } + + @Override + protected boolean hoursGroupsIsEmpty(OrderLine orderLine) { + return orderLine.getHoursGroups().isEmpty(); + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/IHoursGroupHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/IHoursGroupHandler.java new file mode 100644 index 000000000..fa6718cb3 --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/IHoursGroupHandler.java @@ -0,0 +1,76 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.orders.entities; + +import java.util.Set; + +/** + * + * @author Susana Montes Pedreira + * @author Diego Pino Garcia + */ +public interface IHoursGroupHandler { + + /** + * Calculates the total number of working hours in a set of + * {@link HoursGroup}. + * @param hoursGroups + * A {@link HoursGroup} set + * @return The sum of working hours + */ + Integer calculateTotalHours(Set hoursGroups); + + /** + * Checks if the percentage is or not valid. That means, if the pertentage + * of all {@link HoursGroup} with FIXED_PERCENTAGE isn't more than 100%. + * This method is called from setPercentage at {@link HoursGroup} class. + * @return true if the percentage is valid + */ + boolean isPercentageValid(final Set hoursGroups); + + /** + * Checks if the desired total number of hours is valid taking into account + * {@link HoursGroup} policy restrictions. + * @param total + * The desired value + * @return true if the value is valid + */ + boolean isTotalHoursValid(Integer total, final Set hoursGroups); + + /** + * Re-calculates the working hours and percentages in the {@link HoursGroup} + * set of the current {@link OrderLine}, taking into account the policy of + * each {@link HoursGroup}. + */ + void recalculateHoursGroups(T orderLine); + + /** + * Set the total working hours of the {@link OrderLine} taking into account + * the {@link HoursGroup} policies. + * @param workHours + * The desired value to set as total working hours + * @throws IllegalArgumentException + * If parameter is less than 0 or if it's not possible to set + * this value taking into account {@link HoursGroup} policies. + */ + void setWorkHours(T orderLine, Integer workHours) throws IllegalArgumentException; + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java index 80b2654de..b27e9305c 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderElement.java @@ -59,7 +59,6 @@ import org.navalplanner.business.qualityforms.entities.TaskQualityForm; import org.navalplanner.business.requirements.entities.CriterionRequirement; import org.navalplanner.business.requirements.entities.DirectCriterionRequirement; import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; -import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.templates.entities.OrderElementTemplate; import org.navalplanner.business.trees.ITreeNode; @@ -83,13 +82,12 @@ public abstract class OrderElement extends BaseEntity implements private Set taskQualityForms = new HashSet(); - private Set criterionRequirements = new HashSet(); protected OrderLineGroup parent; - protected CriterionRequirementHandler criterionRequirementHandler = CriterionRequirementHandler - .getInstance(); + protected CriterionRequirementOrderElementHandler criterionRequirementHandler = + CriterionRequirementOrderElementHandler.getInstance(); private SchedulingState.Type schedulingStateType = Type.NO_SCHEDULED; @@ -576,32 +574,27 @@ public abstract class OrderElement extends BaseEntity implements protected void removeCriterionRequirement(CriterionRequirement requirement) { criterionRequirements.remove(requirement); - if(requirement instanceof IndirectCriterionRequirement){ + if (requirement instanceof IndirectCriterionRequirement) { ((IndirectCriterionRequirement)requirement).getParent(). getChildren().remove((IndirectCriterionRequirement)requirement); } } - public void addDirectCriterionRequirement( - CriterionRequirement newRequirement) { - if (criterionRequirementHandler.canAddCriterionRequirement(this, - newRequirement)) { - basicAddCriterionRequirement(newRequirement); - criterionRequirementHandler - .propagateDirectCriterionRequirementAddition(this, - newRequirement); - } else { - Criterion criterion = newRequirement.getCriterion(); - throw new IllegalStateException(_( - " The {0} already exist into other order element", - criterion - .getName())); - } + @Override + public void addCriterionRequirement( + CriterionRequirement criterionRequirement) { + criterionRequirementHandler.addCriterionRequirement(this, criterionRequirement); } - void addIndirectCriterionRequirement( + public void addDirectCriterionRequirement( + CriterionRequirement criterionRequirement) { + criterionRequirementHandler.addDirectCriterionRequirement(this, criterionRequirement); + } + + public void addIndirectCriterionRequirement( IndirectCriterionRequirement criterionRequirement) { - basicAddCriterionRequirement(criterionRequirement); + criterionRequirementHandler.addIndirectCriterionRequirement(this, + criterionRequirement); } protected void basicAddCriterionRequirement( @@ -610,34 +603,11 @@ public abstract class OrderElement extends BaseEntity implements this.criterionRequirements.add(criterionRequirement); } - @Override - public void addCriterionRequirement( - CriterionRequirement criterionRequirement) { - if (criterionRequirement instanceof DirectCriterionRequirement) { - addDirectCriterionRequirement((DirectCriterionRequirement) criterionRequirement); - } else { // criterionRequirement instanceof IndirectCriterionRequirement - addIndirectCriterionRequirement((IndirectCriterionRequirement) criterionRequirement); - } - } - public void updateCriterionRequirements() { - updateMyCriterionRequirements(); + criterionRequirementHandler.updateMyCriterionRequirements(this); criterionRequirementHandler.propagateUpdateCriterionRequirements(this); } - void updateMyCriterionRequirements() { - OrderElement newParent = this.getParent(); - Set requirementsParent = newParent - .getCriterionRequirements(); - Set currentIndirects = criterionRequirementHandler - .getCurrentIndirectRequirements( - getIndirectCriterionRequirement(), requirementsParent); - criterionRequirementHandler.transformDirectToIndirectIfNeeded(this, - currentIndirects); - criterionRequirementHandler.removeOldIndirects(this, currentIndirects); - criterionRequirementHandler.addNewsIndirects(this, currentIndirects); - } - public boolean canAddCriterionRequirement( DirectCriterionRequirement newRequirement) { return criterionRequirementHandler.canAddCriterionRequirement(this, @@ -645,13 +615,7 @@ public abstract class OrderElement extends BaseEntity implements } protected Set getIndirectCriterionRequirement() { - Set list = new HashSet(); - for (CriterionRequirement criterionRequirement : criterionRequirements) { - if (criterionRequirement instanceof IndirectCriterionRequirement) { - list.add((IndirectCriterionRequirement) criterionRequirement); - } - } - return list; + return criterionRequirementHandler.getIndirectCriterionRequirement(criterionRequirements); } public void applyStartConstraintIfNeededTo(Task task) { @@ -670,13 +634,8 @@ public abstract class OrderElement extends BaseEntity implements } public Set getDirectCriterionRequirement() { - Set list = new HashSet(); - for (CriterionRequirement criterionRequirement : criterionRequirements) { - if (criterionRequirement instanceof DirectCriterionRequirement) { - list.add((DirectCriterionRequirement) criterionRequirement); - } - } - return list; + return criterionRequirementHandler + .getDirectCriterionRequirement(criterionRequirements); } public SchedulingState.Type getSchedulingStateType() { @@ -748,13 +707,7 @@ public abstract class OrderElement extends BaseEntity implements } public Order getOrder() { - Order order; - try { - order = parent.getOrder(); - } catch (Exception e) { - throw new RuntimeException(e); - } - return order; + return parent.getOrder(); } @Valid diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLine.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLine.java index 32a72f667..029a098fa 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLine.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLine.java @@ -20,8 +20,6 @@ package org.navalplanner.business.orders.entities; -import static org.navalplanner.business.i18n.I18nHelper._; - import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collections; @@ -44,7 +42,10 @@ import org.navalplanner.business.templates.entities.OrderLineTemplate; public class OrderLine extends OrderElement { - private static final String INITIAL_HOURS_GROUP_CODE = "HOURS-GROUP-CODE"; + public static final String INITIAL_HOURS_GROUP_CODE = "HOURS-GROUP-CODE"; + + private HoursGroupOrderLineHandler hoursGroupOrderLineHandler = HoursGroupOrderLineHandler + .getInstance(); public static OrderLine create() { OrderLine result = new OrderLine(); @@ -77,7 +78,7 @@ public class OrderLine extends OrderElement { @Override public Integer getWorkHours() { - return calculateTotalHours(hoursGroups); + return hoursGroupOrderLineHandler.calculateTotalHours(hoursGroups); } @Override @@ -137,289 +138,49 @@ public class OrderLine extends OrderElement { return new ArrayList(hoursGroups); } + public Set myHoursGroups() { + return hoursGroups; + } + + public void setHoursGroups(final Set hoursGroups) { + this.hoursGroups.clear(); + this.hoursGroups.addAll(hoursGroups); + } + public void addHoursGroup(HoursGroup hoursGroup) { hoursGroup.setParentOrderLine(this); hoursGroup.updateMyCriterionRequirements(); - hoursGroups.add(hoursGroup); + doAddHoursGroup(hoursGroup); recalculateHoursGroups(); } + public void doAddHoursGroup(HoursGroup hoursGroup) { + hoursGroups.add(hoursGroup); + } + public void deleteHoursGroup(HoursGroup hoursGroup) { hoursGroups.remove(hoursGroup); recalculateHoursGroups(); } /** - * Set the total working hours of the {@link OrderLine} taking into account - * the {@link HoursGroup} policies. - * @param workHours - * The desired value to set as total working hours - * @throws IllegalArgumentException - * If parameter is less than 0 or if it's not possible to set - * this value taking into account {@link HoursGroup} policies. + * Operations for manipulating {@link HoursGroup} */ + public void setWorkHours(Integer workHours) throws IllegalArgumentException { - - if (workHours == null) { - workHours = new Integer(0); - } - - if (workHours < 0) { - throw new IllegalArgumentException( - _("workHours should be greater or equals to 0")); - } - - if (hoursGroups.isEmpty()) { - HoursGroup hoursGroup = HoursGroup.create(this); - hoursGroup.setWorkingHours(workHours); - hoursGroup.setPercentage((new BigDecimal(1).setScale(2))); - hoursGroup.setCode(INITIAL_HOURS_GROUP_CODE); - hoursGroups.add(hoursGroup); - } else { - - if (!isTotalHoursValid(workHours)) { - throw new IllegalArgumentException( - _("\"workHours\" value is not valid, taking into " - + "account the current list of HoursGroup")); - } - - updateHoursGroups(workHours); - } + hoursGroupOrderLineHandler.setWorkHours(this, workHours); } - /** - * Makes the needed modifications in hoursGroups attribute in order to set - * the desired value of working hours. This method takes into account the - * different {@link HoursGroup} policies: If policy is FIXED_PERCENTAGE the - * new value is calculated for each {@link HoursGroup} with this policy. - * Using round down in order to avoid problems. Hours are proportionally - * distributed when there're {@link HoursGroup} with NO_FIXED policy. - * Finally, it creates new {@link HoursGroup} if the're some remaining hours - * (it could happen because of the round down used for operations). - * @param workHours - * The value to set as total working hours - */ - private void updateHoursGroups(Integer workHours) { - - Set newHoursGroups = new HashSet(); - - // Divide HourGroup depending on policy - Set fixedPercentageGroups = new HashSet(); - Set noFixedGroups = new HashSet(); - - for (HoursGroup hoursGroup : hoursGroups) { - if (hoursGroup.isFixedPercentage()) { - fixedPercentageGroups.add(hoursGroup); - } else { - noFixedGroups.add(hoursGroup); - } - } - - // For every HourGroup with FIXED_PERCENTAGE, workingHours will be - // calculated - for (HoursGroup hoursGroup : fixedPercentageGroups) { - Integer hours = hoursGroup.getPercentage().multiply( - new BigDecimal(workHours).setScale(2)).toBigInteger() - .intValue(); - hoursGroup.setWorkingHours(hours); - newHoursGroups.add(hoursGroup); - } - - Integer newTotal = calculateTotalHours(newHoursGroups); - - if (newTotal.compareTo(workHours) > 0) { - throw new RuntimeException("Unreachable code"); - } else if (newTotal.compareTo(workHours) == 0) { - for (HoursGroup hoursGroup : noFixedGroups) { - hoursGroup.setWorkingHours(0); - newHoursGroups.add(hoursGroup); - } - } else if (newTotal.compareTo(workHours) < 0) { - // Proportional sharing - Integer oldNoFixed = calculateTotalHoursNoFixed(hoursGroups); - Integer newNoFixed = workHours - newTotal; - - for (HoursGroup hoursGroup : noFixedGroups) { - Integer newHours; - if (oldNoFixed == 0) { - newHours = (int) ((float) newNoFixed / hoursGroups.size()); - } else { - newHours = (int) ((float) hoursGroup.getWorkingHours() - / oldNoFixed * newNoFixed); - } - hoursGroup.setWorkingHours(newHours); - - newHoursGroups.add(hoursGroup); - } - } - - // If there're remaining hours - newTotal = calculateTotalHours(newHoursGroups); - if (newTotal.compareTo(workHours) < 0) { - // Add a new HourGroup with the remaining hours - HoursGroup hoursGroup = HoursGroup.create(this); - hoursGroup.setWorkingHours(workHours - newTotal); - - newHoursGroups.add(hoursGroup); - } - - // Set the attribute with the new hours group calculated - hoursGroups = newHoursGroups; - - // Re-calculate percentages - recalculateHoursGroups(); - } - - /** - * Checks if the desired total number of hours is valid taking into account - * {@link HoursGroup} policy restrictions. - * @param total - * The desired value - * @return true if the value is valid - */ public boolean isTotalHoursValid(Integer total) { - - if (total == null) { - return false; - } - - Integer newTotal = 0; - - for (HoursGroup hoursGroup : hoursGroups) { - if (hoursGroup.isFixedPercentage()) { - newTotal += hoursGroup.getPercentage().multiply( - new BigDecimal(total).setScale(2)).toBigInteger() - .intValue(); - } - } - - if (newTotal.compareTo(total) > 0) { - return false; - } - - return true; + return hoursGroupOrderLineHandler.isTotalHoursValid(total, hoursGroups); } - /** - * Checks if the percentage is or not valid. That means, if the pertentage - * of all {@link HoursGroup} with FIXED_PERCENTAGE isn't more than 100%. - * This method is called from setPercentage at {@link HoursGroup} class. - * @return true if the percentage is valid - */ public boolean isPercentageValid() { - - BigDecimal newPercentage = new BigDecimal(0).setScale(2); - - for (HoursGroup hoursGroup : hoursGroups) { - if (hoursGroup.isFixedPercentage()) { - newPercentage = newPercentage.add(hoursGroup.getPercentage()); - } - } - - if (newPercentage.compareTo(new BigDecimal(1).setScale(2)) > 0) { - return false; - } - - return true; + return hoursGroupOrderLineHandler.isPercentageValid(hoursGroups); } - /** - * Calculates the total number of working hours in a set of - * {@link HoursGroup}. - * @param hoursGroups - * A {@link HoursGroup} set - * @return The sum of working hours - */ - private Integer calculateTotalHours(Set hoursGroups) { - Integer result = 0; - for (HoursGroup hoursGroup : hoursGroups) { - Integer workingHours = hoursGroup.getWorkingHours(); - if (workingHours != null) { - result += workingHours; - } - } - return result; - } - - /** - * Calculates the total number of working hours in a set of - * {@link HoursGroup} taking into account just {@link HoursGroup} with - * NO_FIXED as policy. - * @param hoursGroups - * A {@link HoursGroup} set - * @return The sum of NO_FIXED {@link HoursGroup} - */ - private Integer calculateTotalHoursNoFixed(Set hoursGroups) { - Integer result = 0; - for (HoursGroup hoursGroup : hoursGroups) { - if (!hoursGroup.isFixedPercentage()) { - result += hoursGroup.getWorkingHours(); - } - } - return result; - } - - /** - * Re-calculates the working hours and percentages in the {@link HoursGroup} - * set of the current {@link OrderLine}, taking into account the policy of - * each {@link HoursGroup}. - */ public void recalculateHoursGroups() { - Integer total = calculateTotalHours(hoursGroups); - BigDecimal totalBigDecimal = new BigDecimal(total).setScale(2); - - // For each HoursGroup with FIXED_PERCENTAGE, the workingHours are - // calculated - for (HoursGroup hoursGroup : hoursGroups) { - if (hoursGroup.isFixedPercentage()) { - Integer workingHours = hoursGroup.getPercentage().multiply( - totalBigDecimal).toBigInteger().intValue(); - - hoursGroup.setWorkingHours(workingHours); - } - } - - Integer newTotal = calculateTotalHours(hoursGroups); - // If the total was modified - if (!newTotal.equals(total)) { - Integer totalNoFixed = calculateTotalHoursNoFixed(hoursGroups); - - // For each HoursGroup without FIXED_PERCENTAGE, the hours are - // proportionally shared - for (HoursGroup hoursGroup : hoursGroups) { - if (!hoursGroup.isFixedPercentage()) { - Integer hours = hoursGroup.getWorkingHours(); - Integer newHours = (int) (((float) hours / totalNoFixed) * (total - (newTotal - totalNoFixed))); - hoursGroup.setWorkingHours(newHours); - } - } - } - - newTotal = calculateTotalHours(hoursGroups); - // If there's still some remaining hours - if (newTotal.compareTo(total) < 0) { - // Add a new HourGroup with the remaining hours - HoursGroup hoursGroup = HoursGroup.create(this); - hoursGroup.updateMyCriterionRequirements(); - hoursGroup.setWorkingHours(total - newTotal); - hoursGroups.add(hoursGroup); - } - - // Then the percentages for the HoursGroup without FIXED_PERCENTAGE are - // recalculated. - for (HoursGroup hoursGroup : hoursGroups) { - if (!hoursGroup.isFixedPercentage()) { - if (totalBigDecimal.equals(new BigDecimal(0).setScale(2))) { - hoursGroup.setPercentage(new BigDecimal(0).setScale(2)); - } else { - BigDecimal hoursBigDecimal = new BigDecimal(hoursGroup - .getWorkingHours()).setScale(2); - BigDecimal percentage = hoursBigDecimal.divide( - totalBigDecimal, BigDecimal.ROUND_DOWN); - hoursGroup.setPercentage(percentage); - } - } - } + hoursGroupOrderLineHandler.recalculateHoursGroups(this); } @Override @@ -480,7 +241,7 @@ public class OrderLine extends OrderElement { } protected void copyRequirementToOrderElement(OrderLineGroup container) { - criterionRequirementHandler.copyRequirementToOrderElement(this, + criterionRequirementHandler.copyRequirementToOrderLineGroup(this, container); } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLineGroup.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLineGroup.java index 81b6c70c8..da9339ade 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLineGroup.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/entities/OrderLineGroup.java @@ -778,7 +778,7 @@ public class OrderLineGroup extends OrderElement implements } protected void copyRequirementToOrderElement(OrderLine leaf) { - criterionRequirementHandler.copyRequirementToOrderElement(this, leaf); + criterionRequirementHandler.copyRequirementToOrderLine(this, leaf); } @Override diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/CriterionRequirement.java b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/CriterionRequirement.java index 9270736c8..f0af78d36 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/CriterionRequirement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/CriterionRequirement.java @@ -24,6 +24,7 @@ import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.orders.entities.HoursGroup; import org.navalplanner.business.orders.entities.OrderElement; import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.templates.entities.OrderElementTemplate; /** * @@ -31,11 +32,13 @@ import org.navalplanner.business.resources.entities.Criterion; */ public class CriterionRequirement extends BaseEntity{ + private Criterion criterion; + private HoursGroup hoursGroup; private OrderElement orderElement; - private Criterion criterion; + private OrderElementTemplate orderElementTemplate; public CriterionRequirement(){ @@ -46,9 +49,18 @@ public class CriterionRequirement extends BaseEntity{ } public CriterionRequirement(Criterion criterion, - OrderElement orderElement,HoursGroup hoursGroup){ + OrderElement orderElement, HoursGroup hoursGroup){ this.criterion = criterion; this.orderElement = orderElement; + this.orderElementTemplate = null; + this.hoursGroup = hoursGroup; + } + + public CriterionRequirement(Criterion criterion, + OrderElementTemplate orderElementTemplate, HoursGroup hoursGroup){ + this.criterion = criterion; + this.orderElementTemplate = orderElementTemplate; + this.orderElement = null; this.hoursGroup = hoursGroup; } @@ -80,4 +92,12 @@ public class CriterionRequirement extends BaseEntity{ public boolean isValid() { return true; } + + public OrderElementTemplate getOrderElementTemplate() { + return orderElementTemplate; + } + + public void setOrderElementTemplate(OrderElementTemplate orderElementTemplate) { + this.orderElementTemplate = orderElementTemplate; + } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/DirectCriterionRequirement.java b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/DirectCriterionRequirement.java index 988e3dc4d..694725f83 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/DirectCriterionRequirement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/DirectCriterionRequirement.java @@ -23,20 +23,63 @@ package org.navalplanner.business.requirements.entities; import java.util.HashSet; import java.util.Set; +import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.orders.entities.HoursGroup; import org.navalplanner.business.orders.entities.OrderElement; import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.templates.entities.OrderElementTemplate; /** * * @author Susana Montes Pedreira + * @author Diego Pino Garcia */ public class DirectCriterionRequirement extends CriterionRequirement{ + private DirectCriterionRequirement origin; private Set children = new HashSet(); + public static DirectCriterionRequirement copyFrom( + DirectCriterionRequirement criterionRequirement, + OrderElementTemplate orderElementTemplate) { + DirectCriterionRequirement result = copyFrom(criterionRequirement); + result.setOrigin(criterionRequirement); + result.setOrderElement(null); + result.setOrderElementTemplate(orderElementTemplate); + return result; + } + + public static DirectCriterionRequirement copyFrom( + DirectCriterionRequirement criterionRequirement, + OrderElement orderElement) { + DirectCriterionRequirement result = copyFrom(criterionRequirement); + result.setOrigin(criterionRequirement); + result.setOrderElement(orderElement); + result.setOrderElementTemplate(null); + return result; + } + + public static DirectCriterionRequirement copyFrom( + DirectCriterionRequirement criterionRequirement, + HoursGroup hoursGroup) { + DirectCriterionRequirement result = copyFrom(criterionRequirement); + result.setOrigin(criterionRequirement); + result.setHoursGroup(hoursGroup); + result.setOrderElement(null); + result.setOrderElementTemplate(null); + return result; + } + + public static DirectCriterionRequirement copyFrom( + DirectCriterionRequirement criterionRequirement) { + DirectCriterionRequirement result = DirectCriterionRequirement.create(); + result.setCriterion(criterionRequirement.getCriterion()); + result.setHoursGroup(criterionRequirement.getHoursGroup()); + return BaseEntity.create(result); + } + public static DirectCriterionRequirement create(){ DirectCriterionRequirement result = new DirectCriterionRequirement(); result.setNewObject(true); @@ -57,8 +100,8 @@ public class DirectCriterionRequirement extends CriterionRequirement{ return result; } + protected DirectCriterionRequirement() { - public DirectCriterionRequirement(){ } public DirectCriterionRequirement(Criterion criterion, @@ -70,12 +113,28 @@ public class DirectCriterionRequirement extends CriterionRequirement{ super(criterion); } + public void addIndirectCriterionRequirement(IndirectCriterionRequirement indirect) { + children.add(indirect); + } + + public void removeIndirectCriterionRequirement(IndirectCriterionRequirement indirect) { + children.remove(indirect); + } + public Set getChildren() { return children; } - public void setChildren(Set - children) { + public void setChildren(Set children) { this.children = children; } + + public DirectCriterionRequirement getOrigin() { + return origin; + } + + public void setOrigin(DirectCriterionRequirement origin) { + this.origin = origin; + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/IndirectCriterionRequirement.java b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/IndirectCriterionRequirement.java index b06f5fad4..b4db35d7b 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/IndirectCriterionRequirement.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/requirements/entities/IndirectCriterionRequirement.java @@ -22,34 +22,34 @@ package org.navalplanner.business.requirements.entities; import org.apache.commons.lang.BooleanUtils; import org.hibernate.validator.NotNull; +import org.navalplanner.business.common.BaseEntity; import org.navalplanner.business.orders.entities.HoursGroup; import org.navalplanner.business.orders.entities.OrderElement; import org.navalplanner.business.resources.entities.Criterion; +import org.navalplanner.business.templates.entities.OrderElementTemplate; /** * * @author Susana Montes Pedreira + * @author Diego Pino Garcia */ public class IndirectCriterionRequirement extends CriterionRequirement{ - private DirectCriterionRequirement parent; + private DirectCriterionRequirement parent; - private Boolean valid = true; + private Boolean valid = true; - public static IndirectCriterionRequirement create(DirectCriterionRequirement - parent,Criterion criterion) { - IndirectCriterionRequirement result = new IndirectCriterionRequirement(criterion); - result.setNewObject(true); - result.setParent(parent); - return result; + public static IndirectCriterionRequirement create(IndirectCriterionRequirement criterionRequirement) { + return create(criterionRequirement.getParent(), criterionRequirement.getCriterion()); } - public static IndirectCriterionRequirement create(DirectCriterionRequirement - parent, Criterion criterion,OrderElement orderElement,HoursGroup hoursGroup){ - IndirectCriterionRequirement result = new IndirectCriterionRequirement(parent,criterion, - orderElement,hoursGroup); + public static IndirectCriterionRequirement create( + DirectCriterionRequirement parent, Criterion criterion) { + IndirectCriterionRequirement result = new IndirectCriterionRequirement( + criterion); result.setNewObject(true); + result.setParent(parent); return result; } @@ -66,7 +66,12 @@ public class IndirectCriterionRequirement extends CriterionRequirement{ public IndirectCriterionRequirement(DirectCriterionRequirement parent,Criterion criterion, OrderElement orderElement,HoursGroup hoursGroup){ - super(criterion,orderElement,hoursGroup); + super(criterion, orderElement, hoursGroup); + } + + public IndirectCriterionRequirement(DirectCriterionRequirement parent, Criterion criterion, + OrderElementTemplate orderElementTemplate, HoursGroup hoursGroup){ + super(criterion, orderElementTemplate, hoursGroup); } @NotNull(message = "parent not specified") diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/CriterionRequirementTemplateHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/CriterionRequirementTemplateHandler.java new file mode 100644 index 000000000..a80684fbd --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/CriterionRequirementTemplateHandler.java @@ -0,0 +1,240 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.templates.entities; + +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.navalplanner.business.orders.entities.CriterionRequirementHandler; +import org.navalplanner.business.orders.entities.HoursGroup; +import org.navalplanner.business.orders.entities.OrderElement; +import org.navalplanner.business.requirements.entities.CriterionRequirement; +import org.navalplanner.business.requirements.entities.DirectCriterionRequirement; +import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; +import org.navalplanner.business.resources.entities.Criterion; + +/** + * + * @author Diego Pino Garcia + * + */ +public class CriterionRequirementTemplateHandler extends + CriterionRequirementHandler{ + + private static final CriterionRequirementTemplateHandler singleton = + new CriterionRequirementTemplateHandler(); + + private CriterionRequirementTemplateHandler() { + + } + + public static CriterionRequirementTemplateHandler getInstance() { + return singleton; + } + + @Override + protected void addIndirectCriterionRequirementToOrderLine( + OrderLineTemplate orderLine, IndirectCriterionRequirement indirect) { + orderLine.addIndirectCriterionRequirement(indirect); + } + + @Override + protected void basicAddCriterionRequirement( + OrderElementTemplate orderElement, + CriterionRequirement criterionRequirement) { + orderElement.basicAddCriterionRequirement(criterionRequirement); + } + + @Override + protected void basicAddCriterionRequirementIntoOrderLineGroup( + OrderLineGroupTemplate orderLineGroup, + CriterionRequirement criterionRequirement) { + orderLineGroup.basicAddCriterionRequirement(criterionRequirement); + } + + @Override + protected List getAllChildren( + OrderElementTemplate orderElement) { + return orderElement.getAllChildren(); + } + + @Override + protected List getChildren( + OrderElementTemplate orderElement) { + return orderElement.getChildren(); + } + + @Override + protected Set getCriterionRequirements( + OrderElementTemplate orderElement) { + return orderElement.getCriterionRequirements(); + } + + @Override + protected Set getDirectCriterionRequirement( + OrderElementTemplate orderElement) { + return orderElement.getDirectCriterionRequirements(); + } + + @Override + protected Set getDirectCriterionRequirementFromOrderLine( + OrderLineTemplate orderLine) { + return orderLine.getDirectCriterionRequirements(); + } + + @Override + protected Set getDirectCriterionRequirementFromOrderLineGroup( + OrderLineGroupTemplate orderLineGroup) { + return orderLineGroup.getDirectCriterionRequirements(); + } + + @Override + protected List getHoursGroups(OrderLineTemplate orderline) { + return orderline.getHoursGroups(); + } + + @Override + protected Set getIndirectCriterionRequirement( + OrderElementTemplate orderElement) { + return orderElement.getIndirectCriterionRequirement(); + } + + @Override + protected Set getIndirectCriterionRequirementFromOrderLine( + OrderLineTemplate orderLine) { + return orderLine.getIndirectCriterionRequirement(); + } + + @Override + protected Set getIndirectCriterionRequirementFromOrderLineGroup( + OrderLineGroupTemplate orderLineGroup) { + return orderLineGroup.getIndirectCriterionRequirement(); + } + + @Override + protected List getOrderLineGroupChildren( + OrderLineGroupTemplate orderLineGroup) { + return orderLineGroup.getChildren(); + } + + @Override + protected List getOrderLineHoursGroups( + OrderLineTemplate orderLine) { + return orderLine.getHoursGroups(); + } + + @Override + protected OrderElementTemplate getParent(OrderElementTemplate orderElement) { + return orderElement.getParent(); + } + + @Override + protected boolean isOrderLine(OrderElementTemplate orderElement) { + return (orderElement instanceof OrderLineTemplate); + } + + @Override + protected boolean isOrderLineGroup(OrderElementTemplate orderElement) { + return (orderElement instanceof OrderLineGroupTemplate); + } + + @Override + protected void removeCriterionRequirement( + OrderElementTemplate orderElement, + CriterionRequirement criterionRequirement) { + orderElement.removeCriterionRequirement(criterionRequirement); + } + + @Override + protected OrderElementTemplate toOrderElement(OrderLineTemplate orderLine) { + return (OrderElementTemplate) orderLine; + } + + @Override + protected OrderLineTemplate toOrderLine(OrderElementTemplate orderElement) { + return (OrderLineTemplate) orderElement; + } + + @Override + protected OrderLineGroupTemplate toOrderLineGroup( + OrderElementTemplate orderElement) { + return (OrderLineGroupTemplate) orderElement; + } + + @Override + protected Collection myHoursGroups(OrderLineTemplate orderline) { + return orderline.myHoursGroups(); + } + + @Override + public void copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + OrderLineGroupTemplate orderLineGroup, + DirectCriterionRequirement parent) { + + final List orderElements = orderLineGroup.getChildren(); + final Criterion criterion = parent.getCriterion(); + final Set originalIndirectCriterionRequirements = parent + .getOrigin().getChildren(); + final Map> mapTemplateCriterion = + createOrderElementCriterionMap(originalIndirectCriterionRequirements); + + for (OrderElementTemplate each : orderElements) { + Map criterionMap = mapTemplateCriterion + .get(each.getOrigin()); + if (criterionMap != null) { + IndirectCriterionRequirement indirect = IndirectCriterionRequirement + .create(parent, criterion); + indirect.setValid(criterionMap.get(criterion)); + addIndirectCriterionRequirement(each, indirect); + } + + if (isOrderLineGroup(each)) { + copyIndirectCriterionRequirementsFromOriginalToOrderLineGroupChildren( + toOrderLineGroup(each), parent); + } + } + + } + + private Map> createOrderElementCriterionMap( + Set indirects) { + + Map> result = + new HashMap>(); + + for (IndirectCriterionRequirement each: indirects) { + final OrderElement orderElement = each.getOrderElement(); + if (orderElement != null) { + Map value = result.get(orderElement); + if (value == null) { + value = new HashMap(); + } + value.put(each.getCriterion(), each.isValid()); + result.put(orderElement, value); + } + } + return result; + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/HoursGroupOrderLineTemplateHandler.java b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/HoursGroupOrderLineTemplateHandler.java new file mode 100644 index 000000000..4b5a70834 --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/HoursGroupOrderLineTemplateHandler.java @@ -0,0 +1,72 @@ +/* + * This file is part of NavalPlan + * + * Copyright (C) 2009 Fundación para o Fomento da Calidade Industrial e + * Desenvolvemento Tecnolóxico de Galicia + * + * 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.templates.entities; + +import java.util.Set; + +import org.navalplanner.business.orders.entities.HoursGroup; +import org.navalplanner.business.orders.entities.HoursGroupHandler; + +/** + * + * @author Diego Pino Garcia + * + */ +public class HoursGroupOrderLineTemplateHandler extends HoursGroupHandler { + + private static final HoursGroupOrderLineTemplateHandler singleton = + new HoursGroupOrderLineTemplateHandler(); + + private HoursGroupOrderLineTemplateHandler() { + + } + + public static HoursGroupOrderLineTemplateHandler getInstance() { + return singleton; + } + + @Override + protected HoursGroup createHoursGroup(OrderLineTemplate orderLine) { + return HoursGroup.create(orderLine); + } + + @Override + protected Set getHoursGroup(OrderLineTemplate orderLine) { + return orderLine.myHoursGroups(); + } + + @Override + protected void setHoursGroups(OrderLineTemplate orderLine, + Set hoursGroups) { + orderLine.setHoursGroups(hoursGroups); + } + + @Override + protected void addHoursGroup(OrderLineTemplate orderLine, HoursGroup hoursGroup) { + orderLine.doAddHoursGroup(hoursGroup); + } + + @Override + protected boolean hoursGroupsIsEmpty(OrderLineTemplate orderLine) { + return orderLine.getHoursGroups().isEmpty(); + } + +} diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/OrderElementTemplate.java b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/OrderElementTemplate.java index 4d3d9f23c..099bd4bbe 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/OrderElementTemplate.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/templates/entities/OrderElementTemplate.java @@ -46,6 +46,8 @@ import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.labels.entities.Label; import org.navalplanner.business.materials.entities.MaterialAssignment; import org.navalplanner.business.materials.entities.MaterialAssignmentTemplate; +import org.navalplanner.business.orders.entities.HoursGroup; +import org.navalplanner.business.orders.entities.ICriterionRequirable; import org.navalplanner.business.orders.entities.InfoComponent; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.orders.entities.OrderElement; @@ -55,6 +57,9 @@ import org.navalplanner.business.orders.entities.SchedulingState.ITypeChangedLis import org.navalplanner.business.orders.entities.SchedulingState.Type; import org.navalplanner.business.qualityforms.entities.QualityForm; import org.navalplanner.business.templates.daos.IOrderElementTemplateDAO; +import org.navalplanner.business.requirements.entities.CriterionRequirement; +import org.navalplanner.business.requirements.entities.DirectCriterionRequirement; +import org.navalplanner.business.requirements.entities.IndirectCriterionRequirement; import org.navalplanner.business.trees.ITreeNode; /** @@ -62,11 +67,35 @@ import org.navalplanner.business.trees.ITreeNode; * */ public abstract class OrderElementTemplate extends BaseEntity implements - ITreeNode { + ICriterionRequirable, ITreeNode { private static final Log LOG = LogFactory .getLog(OrderElementTemplate.class); + private SchedulingState.Type schedulingStateType; + + private InfoComponent infoComponent; + + private Integer startAsDaysFromBeginning; + + private Integer deadlineAsDaysFromBeginning; + + private OrderLineGroupTemplate parent; + + private Set criterionRequirements = new HashSet(); + + private Set materialAssignments = new HashSet(); + + private Set