From e62f1f51bda51ee35470a3e91c85c06c60e974fe Mon Sep 17 00:00:00 2001 From: Diego Pino Garcia Date: Mon, 7 Sep 2009 01:06:17 +0200 Subject: [PATCH] ItEr24S08CUAsignacionGrupoRecursosAPlanificacionItEr23S10: Revamped ResourceAllocation Error on loading Task after deleting one ResourceAllocation and Cancel --- .../business/planner/entities/Task.java | 41 +++ .../business/resources/daos/IResourceDAO.java | 10 + .../business/resources/daos/ResourceDAO.java | 18 ++ .../business/resources/entities/Resource.java | 4 + .../business/resources/entities/Worker.java | 9 + .../web/planner/IResourceAllocationModel.java | 152 ++++----- .../planner/ResourceAllocationController.java | 260 +++++++++++----- .../web/planner/ResourceAllocationModel.java | 293 ++++++++++++------ .../src/main/webapp/planner/order.zul | 62 ++-- 9 files changed, 585 insertions(+), 264 deletions(-) diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/Task.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/Task.java index 533f046c5..26109c63d 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/Task.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/Task.java @@ -79,6 +79,10 @@ public class Task extends TaskElement { resourceAllocations.remove(resourceAllocation); } + public Boolean getFixedDuration() { + return fixedDuration; + } + public void setFixedDuration(Boolean fixed_duration) { this.fixedDuration = fixed_duration; } @@ -207,4 +211,41 @@ public class Task extends TaskElement { } return result; } + + public Set getGenericResourceAllocations() { + Set result = new HashSet(); + + Set resourceAllocations = getResourceAllocations(); + for (ResourceAllocation resourceAllocation : resourceAllocations) { + if (resourceAllocation instanceof GenericResourceAllocation) { + result.add((GenericResourceAllocation) resourceAllocation); + } + } + + return result; + } + + public Set getSpecificResourceAllocations() { + Set result = new HashSet(); + + Set resourceAllocations = getResourceAllocations(); + for (ResourceAllocation resourceAllocation : resourceAllocations) { + if (resourceAllocation instanceof SpecificResourceAllocation) { + result.add((SpecificResourceAllocation) resourceAllocation); + } + } + + return result; + } + + public BigDecimal getSumPercentage( + List resourceAllocations) { + BigDecimal result = new BigDecimal(0); + + for (ResourceAllocation resourceAllocation : resourceAllocations) { + result = result.add(resourceAllocation.getPercentage()); + } + + return result; + } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java index 771c1b45e..9d38455ea 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/IResourceDAO.java @@ -1,15 +1,25 @@ package org.navalplanner.business.resources.daos; import java.util.List; +import java.util.Set; import org.navalplanner.business.common.daos.IGenericDAO; +import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Worker; /** * DAO interface for the Resource entity. + * * @author Fernando Bellas Permuy + * @author Diego Pino Garcia */ public interface IResourceDAO extends IGenericDAO { public List getWorkers(); + + /** + * Returns all {@link Resource} which satisfy a set of {@link Criterion} + */ + List getAllByCriterions(Set criterions); + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java index 2eb1bb338..488951c45 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/daos/ResourceDAO.java @@ -1,8 +1,11 @@ package org.navalplanner.business.resources.daos; import java.util.List; +import java.util.Set; +import org.hibernate.Query; import org.navalplanner.business.common.daos.GenericDAOHibernate; +import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Worker; import org.springframework.beans.factory.config.BeanDefinition; @@ -11,7 +14,9 @@ import org.springframework.stereotype.Repository; /** * Hibernate DAO for the Resource entity. + * * @author Fernando Bellas Permuy + * @author Diego Pino Garcia */ @Repository @Scope(BeanDefinition.SCOPE_SINGLETON) @@ -21,4 +26,17 @@ public class ResourceDAO extends GenericDAOHibernate implements public List getWorkers() { return list(Worker.class); } + + @Override + public List getAllByCriterions(Set criterions) { + String strQuery = "SELECT resource " + + "FROM Resource resource " + + "LEFT OUTER JOIN resource.criterionSatisfactions criterionSatisfactions " + + "LEFT OUTER JOIN criterionSatisfactions.criterion criterion " + + "WHERE criterion IN (:criterions)"; + Query query = getSession().createQuery(strQuery); + query.setParameterList("criterions", criterions); + return (List) query.list(); + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java index 0fa3871b8..e3df0e74b 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Resource.java @@ -34,6 +34,10 @@ public abstract class Resource extends BaseEntity{ private Set criterionSatisfactions = new HashSet(); + public Set getCriterionSatisfactions() { + return criterionSatisfactions; + } + public abstract String getDescription(); private interface IPredicate { diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java index 708f0149f..97562a30b 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/resources/entities/Worker.java @@ -1,5 +1,8 @@ package org.navalplanner.business.resources.entities; +import java.util.ArrayList; +import java.util.Set; + import org.hibernate.validator.Min; import org.hibernate.validator.NotEmpty; @@ -94,4 +97,10 @@ public class Worker extends Resource { return dailyHours; } + public boolean satisfiesCriterions(Set criterions) { + ICriterion compositedCriterion = CriterionCompounder.buildAnd( + new ArrayList(criterions)).getResult(); + return compositedCriterion.isSatisfiedBy(this); + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/IResourceAllocationModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/IResourceAllocationModel.java index 384a35a60..3910ca8ea 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/IResourceAllocationModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/IResourceAllocationModel.java @@ -1,7 +1,9 @@ package org.navalplanner.web.planner; +import java.math.BigDecimal; import java.util.Set; +import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourceAllocation; import org.navalplanner.business.planner.entities.SpecificResourceAllocation; import org.navalplanner.business.planner.entities.Task; @@ -12,9 +14,72 @@ import org.navalplanner.business.resources.entities.Worker; * Contract for {@link Task}. * * @author Manuel Rego Casasnovas + * @author Diego Pino García */ public interface IResourceAllocationModel { + /** + * Adds a new {@link GenericResourceAllocation} to the current {@link Task}. + */ + void addGenericResourceAllocation(); + + /** + * Adds {@link SpecificResourceAllocation} to {@link Task} + * {@link ResourceAllocation} list + * + * If a {@link SpecificResourceAllocation} satisfies {@link Task} criterions + * one of the {@link GenericResourceAllocation} assigned to + * {@link ResourceAllocation} is removed (in case any exists) + * + */ + void addSpecificResourceAllocation(Worker worker) throws Exception; + + /** + * Returns {@link Set} of {@link Criterion} of the current {@link Task} + * + * @return + */ + Set getCriterions(); + + /** + * Returns {@link Set} of {@link GenericResourceAllocation} of current + * + * @return + */ + Set getGenericResourceAllocations(); + + /** + * Returns number of {@link ResourceAllocation} which are candidate to add + * as {@link GenericResourceAllocation} + * + * @return + */ + int getNumberUnassignedResources(); + + /** + * Returns the {@link Set} of {@link ResourceAllocation} of the current + * {@link Task}. + * + * @return A {@link Set} of {@link ResourceAllocation} + */ + Set getResourceAllocations(); + + /** + * Return sum of percentages for current {@link Task} + * {@link ResourceAllocation} + * + * @return + */ + BigDecimal getSumPercentageResourceAllocations(); + + /** + * Return sum of percentages for current {@link Task} + * {@link SpecificResourceAllocation} + * + * @return + */ + BigDecimal getSumPercentageSpecificResourceAllocations(); + /** * Gets the current {@link Task} object. * @@ -22,11 +87,6 @@ public interface IResourceAllocationModel { */ Task getTask(); - /** - * Adds a new {@link ResourceAllocation} to the current {@link Task}. - */ - void addResourceAllocation(); - /** * Removes the {@link ResourceAllocation} from the current {@link Task}. * @@ -36,72 +96,13 @@ public interface IResourceAllocationModel { void removeResourceAllocation(ResourceAllocation resourceAllocation); /** - * Tries to find a {@link Worker} with the specified NIF. - * - * @param nif - * The NIF to search the {@link Worker} - * @return The {@link Worker} with this NIF or null if it's not - * found - */ - Worker findWorkerByNif(String nif); - - /** - * Relates a {@link Worker} and a {@link Task} through a - * {@link SpecificResourceAllocation}. + * Removes {@link SpecificResourceAllocation} from current {@link Task} + * {@link ResourceAllocation} list * * @param resourceAllocation - * A {@link SpecificResourceAllocation} to set the {@link Worker} - * @param worker - * A {@link Worker} for the {@link SpecificResourceAllocation} */ - void setWorker(SpecificResourceAllocation resourceAllocation, Worker worker); - - /** - * Sets the current {@link Task}, where the user is allocating resources. - * - * @param task - * A {@link Task} - */ - void setTask(Task task); - - /** - * Gets the {@link Set} of {@link Criterion} of the current task. - * - * @return A {@link Set} of {@link Criterion} - */ - Set getCriterions(); - - /** - * Gets the {@link Set} of {@link ResourceAllocation} of the current task. - * - * @return A {@link Set} of {@link ResourceAllocation} - */ - Set getResourceAllocations(); - - /** - * Sets the current {@link ResourceAllocation} to be rendered. - * - * @param resourceAllocation - * The current {@link ResourceAllocation} - */ - void setResourceAllocation(ResourceAllocation resourceAllocation); - - /** - * Gets the {@link Worker} of the current {@link ResourceAllocation}. - * - * @return A {@link Worker} - */ - Worker getWorker(); - - /** - * Checks if the {@link Worker} of the current {@link ResourceAllocation} - * satisfies the {@link Criterion} of the current {@link Task}. - * - * @return True if the {@link Worker} satisfies the {@link Criterion} - * required. Or if the current {@link Worker} is null. - * Or if the {@link Criterion} list is empty. - */ - boolean workerSatisfiesCriterions(); + void removeSpecificResourceAllocation( + SpecificResourceAllocation resourceAllocation); /** * Sets the current Gantt {@link org.zkoss.ganttz.data.Task ganttTask}, @@ -111,6 +112,14 @@ public interface IResourceAllocationModel { */ void setGanttTask(org.zkoss.ganttz.data.Task ganttTask); + /** + * Sets the current {@link Task}, where the user is allocating resources. + * + * @param task + * A {@link Task} + */ + void setTask(Task task); + /** * Update the duration of the current Gantt * {@link org.zkoss.ganttz.data.Task ganttTask}, depending on the resources @@ -121,10 +130,11 @@ public interface IResourceAllocationModel { void updateGanttTaskDuration(); /** - * Adds {@link SpecificResourceAllocation} to {@link Task} + * Updates {@link GenericResourceAllocation} percentages of current + * {@link Task} * - * @param worker + * @param totalPercentage */ - void addSpecificResourceAllocation(Worker worker); + void updateGenericPercentages(BigDecimal totalPercentage); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationController.java index 382cb2b3c..7cc5087f3 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationController.java @@ -3,24 +3,29 @@ package org.navalplanner.web.planner; import static org.navalplanner.web.I18nHelper._; import java.math.BigDecimal; +import java.util.HashSet; import java.util.List; import java.util.Set; +import org.apache.commons.lang.StringUtils; +import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourceAllocation; import org.navalplanner.business.planner.entities.SpecificResourceAllocation; import org.navalplanner.business.planner.entities.Task; import org.navalplanner.business.resources.entities.Criterion; import org.navalplanner.business.resources.entities.Worker; +import org.navalplanner.web.common.IMessagesForUser; +import org.navalplanner.web.common.Level; +import org.navalplanner.web.common.MessagesForUser; import org.navalplanner.web.common.Util; import org.navalplanner.web.common.components.WorkerSearch; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.SuspendNotAllowedException; -import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.event.Event; import org.zkoss.zk.ui.event.EventListener; -import org.zkoss.zk.ui.util.Clients; +import org.zkoss.zk.ui.event.InputEvent; import org.zkoss.zk.ui.util.GenericForwardComposer; import org.zkoss.zul.Button; import org.zkoss.zul.Decimalbox; @@ -35,6 +40,7 @@ import org.zkoss.zul.api.Window; * Controller for {@link ResourceAllocation} view. * * @author Manuel Rego Casasnovas + * @author Diego Pino Garcia */ @org.springframework.stereotype.Component("resourceAllocationController") @Scope(BeanDefinition.SCOPE_PROTOTYPE) @@ -44,56 +50,36 @@ public class ResourceAllocationController extends GenericForwardComposer { private ResourceAllocationRenderer resourceAllocationRenderer = new ResourceAllocationRenderer(); + private Component messagesContainer; + + private IMessagesForUser messagesForUser; + private Listbox resourcesList; + private Decimalbox genericResourceAllocationPercentage; + private Window window; - public Set getCriterions() { - Set criterions = resourceAllocationModel.getCriterions(); - if (criterions.isEmpty()) { - window.getFellow("requiredCriterions").setVisible(false); - window.getFellow("requiredCriterionsEmpty").setVisible(true); - } else { - window.getFellow("requiredCriterionsEmpty").setVisible(false); - window.getFellow("requiredCriterions").setVisible(true); - } - - return criterions; - } - - public Set getResourceAllocations() { - return resourceAllocationModel.getResourceAllocations(); - } - - public ResourceAllocationRenderer getResourceAllocationRenderer() { - return resourceAllocationRenderer; - } - - public void addResourceAllocation() { - resourceAllocationModel.addResourceAllocation(); - Util.reloadBindings(resourcesList); - } - - public void removeResourceAllocation() { - Set selectedItems = resourcesList.getSelectedItems(); - for (Listitem listitem : selectedItems) { - ResourceAllocation resourceAllocation = (ResourceAllocation) listitem - .getValue(); - resourceAllocationModel.removeResourceAllocation(resourceAllocation); - } - Util.reloadBindings(resourcesList); - } - @Override public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); + messagesForUser = new MessagesForUser(messagesContainer); this.window = (Window) comp; } - + /** + * Shows Resource Allocation window + * + * @param task + * @param ganttTask + */ public void showWindow(Task task, org.zkoss.ganttz.data.Task ganttTask) { resourceAllocationModel.setTask(task); resourceAllocationModel.setGanttTask(ganttTask); + + // Add generic resources to resources list + addGenericResources(); + Util.reloadBindings(window); try { window.doModal(); @@ -104,30 +90,24 @@ public class ResourceAllocationController extends GenericForwardComposer { } } - public void back() { - Set resourceAllocations = resourceAllocationModel.getResourceAllocations(); - for (ResourceAllocation resourceAllocation : resourceAllocations) { - if (((SpecificResourceAllocation) resourceAllocation).getWorker() == null) { - throw new WrongValueException( - window.getFellow("resourcesList"), - _("Worker not valid in some resource allocation")); - } + /** + * Check how many {@link ResourceAllocation} object can be assigned to this + * {@link Task} and add them to {@link ResourceAllocation} list + */ + private void addGenericResources() { + int n = resourceAllocationModel.getNumberUnassignedResources(); + for (int i = 0; i < n; i++) { + resourceAllocationModel.addGenericResourceAllocation(); } - - if (!resourceAllocationModel.getTask() - .isValidResourceAllocationWorkers()) { - throw new WrongValueException(window.getFellow("resourcesList"), - _("There is some Worker assigned twice (or more)")); - } - - Clients.closeErrorBox(window.getFellow("resourcesList")); - - resourceAllocationModel.updateGanttTaskDuration(); - - window.setVisible(false); } - public void showSearchResources(Event e) { + /** + * Shows WorkerSearch window, add picked workers as + * {@link SpecificResourceAllocation} to {@link ResourceAllocation} list + * + * @return + */ + public void showSearchResources() { WorkerSearch workerSearch = new WorkerSearch(); workerSearch.setParent(self.getParent()); workerSearch.afterCompose(); @@ -143,15 +123,99 @@ public class ResourceAllocationController extends GenericForwardComposer { return; } - // Get selected workers and add specificResourceAllocations - List workers = workerSearch.getWorkers(); - for (Worker worker : workers) { - resourceAllocationModel.addSpecificResourceAllocation(worker); - } + addSpecificResourceAllocations(workerSearch.getWorkers()); Util.reloadBindings(resourcesList); } + /** + * Adds a list of {@link Worker} to {@link ResourceAllocation} list + * + * @param workers + */ + private void addSpecificResourceAllocations(List workers) { + for (Worker worker : workers) { + addSpecificResourceAllocation(worker); + } + updateGenericPercentages(); + } + + /** + * Update percentages of {@link GenericResourceAllocation} items when + * genericResourceAllocationPercentage box is changed + * + * @param e + */ + public void updateGenericPercentages(InputEvent e) { + updateGenericPercentages(new BigDecimal((String) e.getValue())); + } + + public void updateGenericPercentages() { + updateGenericPercentages(genericResourceAllocationPercentage.getValue()); + } + + private void updateGenericPercentages(BigDecimal genericPercentage) { + if (genericPercentage != null) { + resourceAllocationModel.updateGenericPercentages(genericPercentage + .divide(new BigDecimal(100))); + } + Util.reloadBindings(resourcesList); + } + + private void addSpecificResourceAllocation(Worker worker) { + try { + resourceAllocationModel.addSpecificResourceAllocation(worker); + } catch (Exception e1) { + messagesForUser.showMessage(Level.ERROR, e1.getMessage()); + } + } + + /** + * Returns list of {@link Criterion} separated by comma + * + * @return + */ + public String getTaskCriterions() { + Set criterionNames = new HashSet(); + + Set criterions = resourceAllocationModel.getCriterions(); + for (Criterion criterion : criterions) { + criterionNames.add(criterion.getName()); + } + + return StringUtils.join(criterionNames, ","); + } + + /** + * Returns hours of {@link Task} + * + * @return + */ + public String getTaskHours() { + Task task = resourceAllocationModel.getTask(); + return (task != null && task.getHours() != null) ? task.getHours() + .toString() : ""; + } + + /** + * Returns type of {@link Task} based on value of fixedDuration attribute + * + * @return + */ + public String getTaskType() { + Task task = resourceAllocationModel.getTask(); + return (task != null && task.getFixedDuration()) ? _("Fixed duration") + : _("Variable duration"); + } + + public Set getResourceAllocations() { + return resourceAllocationModel.getResourceAllocations(); + } + + public ResourceAllocationRenderer getResourceAllocationRenderer() { + return resourceAllocationRenderer; + } + /** * * Renders a {@link SpecificResourceAllocation} item @@ -163,14 +227,25 @@ public class ResourceAllocationController extends GenericForwardComposer { @Override public void render(Listitem item, Object data) throws Exception { - final SpecificResourceAllocation resourceAllocation = (SpecificResourceAllocation) data; + if (data instanceof SpecificResourceAllocation) { + renderSpecificResourceAllocation(item, + (SpecificResourceAllocation) data); + } + if (data instanceof GenericResourceAllocation) { + renderGenericResourceAllocation(item, + (GenericResourceAllocation) data); + } + } + private void renderSpecificResourceAllocation(Listitem item, + final SpecificResourceAllocation resourceAllocation) + throws Exception { item.setValue(resourceAllocation); // Label fields are fixed, can only be viewed appendLabel(item, resourceAllocation.getWorker().getName()); - appendLabel(item, resourceAllocation.getWorker().getNif()); - // Pecentage field is editable + // appendLabel(item, resourceAllocation.getWorker().getNif()); + // Percentage field is editable bindPercentage(appendDecimalbox(item), resourceAllocation); // On click delete button appendButton(item, _("Delete")).addEventListener("onClick", @@ -178,18 +253,43 @@ public class ResourceAllocationController extends GenericForwardComposer { @Override public void onEvent(Event event) throws Exception { - resourceAllocationModel - .removeResourceAllocation(resourceAllocation); - Util.reloadBindings(resourcesList); + removeSpecificResourceAllocation(resourceAllocation); } }); } + private void removeSpecificResourceAllocation( + SpecificResourceAllocation resourceAllocation) { + resourceAllocationModel + .removeSpecificResourceAllocation(resourceAllocation); + updateGenericPercentages(); + Util.reloadBindings(resourcesList); + } + + private void renderGenericResourceAllocation(Listitem item, + final GenericResourceAllocation resourceAllocation) + throws Exception { + item.setValue(resourceAllocation); + + // Set name + appendLabel(item, _("Generic")); + // Set percentage + BigDecimal percentage = resourceAllocation.getPercentage(); + if (!new BigDecimal(0).equals(resourceAllocation.getPercentage())) { + percentage = percentage.scaleByPowerOfTen(2).setScale(2, + BigDecimal.ROUND_CEILING); + } + appendLabel(item, percentage.toString()); + // No buttons + appendLabel(item, ""); + } + /** * Appends {@link Label} to {@link Listitem} * * @param listitem - * @param name value for {@link Label} + * @param name + * value for {@link Label} */ private void appendLabel(Listitem listitem, String name) { Label label = new Label(name); @@ -203,7 +303,8 @@ public class ResourceAllocationController extends GenericForwardComposer { * Appends {@link Button} to {@link Listitem} * * @param listitem - * @param label value for {@link Button} + * @param label + * value for {@link Button} * @return */ private Button appendButton(Listitem listitem, String label) { @@ -245,16 +346,21 @@ public class ResourceAllocationController extends GenericForwardComposer { @Override public BigDecimal get() { - return resourceAllocation.getPercentage().scaleByPowerOfTen(2); + return (resourceAllocation.getPercentage() != null) ? resourceAllocation + .getPercentage().scaleByPowerOfTen(2) + : new BigDecimal(0); } }, new Util.Setter() { @Override public void set(BigDecimal value) { - resourceAllocation - .setPercentage(value.setScale(2).divide( - new BigDecimal(100), BigDecimal.ROUND_DOWN)); + if (value != null) { + value = value.setScale(2).divide(new BigDecimal(100), + BigDecimal.ROUND_DOWN); + updateGenericPercentages(); + decimalbox.setValue(value); + } } }); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationModel.java index 55a486d46..a95de78b4 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/planner/ResourceAllocationModel.java @@ -1,25 +1,28 @@ package org.navalplanner.web.planner; +import static org.navalplanner.web.I18nHelper._; + import java.math.BigDecimal; -import java.util.ArrayList; import java.util.HashSet; +import java.util.Iterator; +import java.util.List; import java.util.Set; -import org.hibernate.LockMode; -import org.hibernate.SessionFactory; import org.navalplanner.business.common.exceptions.InstanceNotFoundException; import org.navalplanner.business.orders.daos.IHoursGroupDAO; import org.navalplanner.business.orders.entities.HoursGroup; import org.navalplanner.business.planner.daos.IResourceAllocationDAO; import org.navalplanner.business.planner.daos.ITaskElementDAO; +import org.navalplanner.business.planner.entities.GenericResourceAllocation; import org.navalplanner.business.planner.entities.ResourceAllocation; import org.navalplanner.business.planner.entities.SpecificResourceAllocation; import org.navalplanner.business.planner.entities.Task; +import org.navalplanner.business.resources.daos.IResourceDAO; import org.navalplanner.business.resources.daos.IWorkerDAO; import org.navalplanner.business.resources.entities.Criterion; -import org.navalplanner.business.resources.entities.CriterionCompounder; import org.navalplanner.business.resources.entities.CriterionSatisfaction; -import org.navalplanner.business.resources.entities.ICriterion; +import org.navalplanner.business.resources.entities.CriterionType; +import org.navalplanner.business.resources.entities.Resource; import org.navalplanner.business.resources.entities.Worker; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; @@ -31,6 +34,7 @@ import org.springframework.transaction.annotation.Transactional; * Model for UI operations related to {@link Task} * * @author Manuel Rego Casasnovas + * @author Diego Pino García */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) @@ -43,10 +47,10 @@ public class ResourceAllocationModel implements IResourceAllocationModel { private IWorkerDAO workerDAO; @Autowired - private SessionFactory sessionFactory; + private IHoursGroupDAO hoursGroupDAO; @Autowired - private IHoursGroupDAO hoursGroupDAO; + private IResourceDAO resourceDAO; @Autowired private IResourceAllocationDAO resourceAllocationDAO; @@ -55,30 +59,110 @@ public class ResourceAllocationModel implements IResourceAllocationModel { private org.zkoss.ganttz.data.Task ganttTask; - private ResourceAllocation resourceAllocation; - - @Override - @Transactional(readOnly = true) - public void setTask(Task task) { - taskElementDAO.save(task); - task.getResourceAllocations().size(); - - HoursGroup hoursGroup = task.getHoursGroup(); - hoursGroupDAO.save(hoursGroup); - hoursGroup.getCriterions().size(); - - this.task = task; - } - @Override public Task getTask() { return task; } @Override - public void addResourceAllocation() { - ResourceAllocation resourceAllocation = SpecificResourceAllocation.create(task); + @Transactional(readOnly = true) + public void setTask(Task task) { + try { + task = (Task) taskElementDAO.find(task.getId()); + reattachResourceAllocations(task.getResourceAllocations()); + hoursGroupDAO.save(task.getHoursGroup()); + reattachHoursGroup(task.getHoursGroup()); + reattachCriterions(task.getHoursGroup().getCriterions()); + + this.task = task; + } catch (InstanceNotFoundException e) { + + } + } + + private void reattachResourceAllocations( + Set resourceAllocations) { + resourceAllocations.size(); + for (ResourceAllocation resourceAllocation : resourceAllocations) { + resourceAllocation.getPercentage(); + if (resourceAllocation instanceof SpecificResourceAllocation) { + reattachSpecificResourceAllocation((SpecificResourceAllocation) resourceAllocation); + } + resourceAllocationDAO.save(resourceAllocation); + } + } + + private void reattachSpecificResourceAllocation( + SpecificResourceAllocation resourceAllocation) { + resourceAllocation.getWorker().getName(); + reattachCriterionSatisfactions(resourceAllocation.getWorker() + .getCriterionSatisfactions()); + } + + private void reattachHoursGroup(HoursGroup hoursGroup) { + hoursGroup.getPercentage(); + } + + private void reattachCriterions(Set criterions) { + for (Criterion criterion : criterions) { + reattachCriterion(criterion); + } + } + + private void reattachCriterion(Criterion criterion) { + criterion.getName(); + reattachCriterionType(criterion.getType()); + } + + private void reattachCriterionType(CriterionType criterionType) { + criterionType.getName(); + } + + @Override + @Transactional(readOnly = true) + public void addGenericResourceAllocation() { + GenericResourceAllocation resourceAllocation = GenericResourceAllocation + .create(task); + resourceAllocation.setPercentage(new BigDecimal(0)); task.addResourceAllocation(resourceAllocation); + taskElementDAO.save(task); + } + + @Override + @Transactional(readOnly = true) + public void addSpecificResourceAllocation(Worker worker) throws Exception { + + // ResourceAllocation already exists + if (findSpecificResourceAllocationByWorker(worker) != null) { + throw new IllegalArgumentException(_( + "{0} already assigned to resource allocation list", worker + .getName())); + } + + // Prepare resourceAllocation + SpecificResourceAllocation resourceAllocation = SpecificResourceAllocation + .create(task); + resourceAllocation.setWorker(worker); + resourceAllocation.setPercentage((new BigDecimal(1))); + + reattachWorker(worker); + // Check if worker was itself a generic resource + if (worker.satisfiesCriterions(getCriterions())) { + Set genericResourceAllocations = getGenericResourceAllocations(); + // Generic resources always match criterions, so we need to remove + // one generic resource to leave room for a specific resource + if (genericResourceAllocations.size() > 0) { + removeResourceAllocation(genericResourceAllocations.iterator() + .next()); + } + } + task.addResourceAllocation(resourceAllocation); + } + + @Override + @Transactional(readOnly = true) + public Set getGenericResourceAllocations() { + return task.getGenericResourceAllocations(); } @Override @@ -86,92 +170,122 @@ public class ResourceAllocationModel implements IResourceAllocationModel { task.removeResourceAllocation(resourceAllocation); } - @Override - @Transactional(readOnly = true) - public Worker findWorkerByNif(String nif) { - try { - return workerDAO.findUniqueByNif(nif); - } catch (InstanceNotFoundException e) { - return null; - } - } - - @Override - public void setWorker(SpecificResourceAllocation resourceAllocation, - Worker worker) { - resourceAllocation.setWorker(worker); - } - @Override public Set getCriterions() { - if (task == null) { - return new HashSet(); - } - return task.getHoursGroup().getCriterions(); + return (task != null) ? task.getHoursGroup().getCriterions() + : new HashSet(); } @Override public Set getResourceAllocations() { - if (task == null) { - return new HashSet(); - } - return task.getResourceAllocations(); + return (task != null) ? task.getResourceAllocations() + : new HashSet(); } @Override @Transactional(readOnly = true) - public void setResourceAllocation(ResourceAllocation resourceAllocation) { - resourceAllocationDAO.save(resourceAllocation); + public void removeSpecificResourceAllocation( + SpecificResourceAllocation resourceAllocation) { + boolean addGenericResourceAllocation = false; - Worker worker = ((SpecificResourceAllocation) resourceAllocation) - .getWorker(); - if (worker != null) { - workerDAO.save(worker); - Set criterionSatisfactions = worker - .getAllSatisfactions(); - for (CriterionSatisfaction criterionSatisfaction : criterionSatisfactions) { - criterionSatisfaction.getCriterion().getName(); - criterionSatisfaction.getCriterion().getType().getName(); + // On removing this resourceAllocation, it may be room for a new generic + // resource allocation + Worker worker = resourceAllocation.getWorker(); + if (worker.satisfiesCriterions(getCriterions())) { + addGenericResourceAllocation = true; + } + resourceAllocationDAO.save(resourceAllocation); + task.removeResourceAllocation(resourceAllocation); + // Add new generic resource + if (addGenericResourceAllocation) { + addGenericResourceAllocation(); + } + } + + @Override + @Transactional(readOnly = true) + public void updateGenericPercentages(BigDecimal totalPercentage) { + Set genericResourceAllocations = getGenericResourceAllocations(); + BigDecimal percentagePerResource = totalPercentage; + + percentagePerResource = percentagePerResource + .subtract(getSumPercentageSpecificResourceAllocations()); + if (genericResourceAllocations.size() > 0) { + percentagePerResource = percentagePerResource.setScale(8).divide( + new BigDecimal(genericResourceAllocations.size()), + BigDecimal.ROUND_DOWN); + + // Percentage cannot be negative + if (percentagePerResource.compareTo(new BigDecimal(0)) < 0) { + percentagePerResource = new BigDecimal(0); + } + + for (ResourceAllocation resourceAllocation : genericResourceAllocations) { + resourceAllocation.setPercentage(percentagePerResource); } } - - this.resourceAllocation = resourceAllocation; } @Override @Transactional(readOnly = true) - public Worker getWorker() { - if (resourceAllocation == null) { - return null; + public BigDecimal getSumPercentageSpecificResourceAllocations() { + return getSumPercentage(task.getSpecificResourceAllocations()); + } + + @SuppressWarnings("unchecked") + private BigDecimal getSumPercentage(Set resourceAllocations) { + BigDecimal result = new BigDecimal(0); + + for (Iterator i = resourceAllocations.iterator(); i.hasNext();) { + ResourceAllocation resourceAllocation = (ResourceAllocation) i + .next(); + result = result.add(resourceAllocation.getPercentage()); } - Worker worker = ((SpecificResourceAllocation) resourceAllocation) - .getWorker(); - if (worker == null) { - return null; + + return result; + } + + private SpecificResourceAllocation findSpecificResourceAllocationByWorker(Worker worker) { + for (SpecificResourceAllocation resourceAllocation : task + .getSpecificResourceAllocations()) { + if (resourceAllocation.getWorker().getId().equals(worker.getId())) { + return resourceAllocation; + } } - try { - return workerDAO.find(worker.getId()); - } catch (InstanceNotFoundException e) { - throw new RuntimeException(e); + return null; + } + + @Transactional(readOnly = true) + private void reattachWorker(Worker worker) { + workerDAO.save(worker); + reattachCriterionSatisfactions(worker.getCriterionSatisfactions()); + } + + private void reattachCriterionSatisfactions( + Set criterionSatisfactions) { + for (CriterionSatisfaction criterionSatisfaction : criterionSatisfactions) { + criterionSatisfaction.getStartDate(); + reattachCriterion(criterionSatisfaction.getCriterion()); } } @Override @Transactional(readOnly = true) - public boolean workerSatisfiesCriterions() { + public BigDecimal getSumPercentageResourceAllocations() { + return getSumPercentage(task.getResourceAllocations()); + } - for (Criterion criterion : getCriterions()) { - sessionFactory.getCurrentSession().lock(criterion, LockMode.NONE); - } + @Override + @Transactional(readOnly = true) + public int getNumberUnassignedResources() { + List resources = resourceDAO + .getAllByCriterions(getCriterions()); + Set resourceAllocations = task + .getResourceAllocations(); - Worker worker = getWorker(); - - if (worker == null) { - return true; - } - ICriterion compositedCriterion = CriterionCompounder.buildAnd( - new ArrayList(getCriterions())).getResult(); - return compositedCriterion.isSatisfiedBy(worker); + return (resources.size() - resourceAllocations.size() > 0) ? resources + .size() + - resourceAllocations.size() : 0; } @Override @@ -187,13 +301,4 @@ public class ResourceAllocationModel implements IResourceAllocationModel { ganttTask.setEndDate(task.getEndDate()); } - @Override - public void addSpecificResourceAllocation(Worker worker) { - SpecificResourceAllocation resourceAllocation = SpecificResourceAllocation - .create(task); - resourceAllocation.setWorker(worker); - resourceAllocation.setPercentage(new BigDecimal(1)); - task.addResourceAllocation(resourceAllocation); - } - -} \ No newline at end of file +} diff --git a/navalplanner-webapp/src/main/webapp/planner/order.zul b/navalplanner-webapp/src/main/webapp/planner/order.zul index 5da0a1ddd..3e403c6ab 100644 --- a/navalplanner-webapp/src/main/webapp/planner/order.zul +++ b/navalplanner-webapp/src/main/webapp/planner/order.zul @@ -64,34 +64,52 @@ apply="${allocationController}" title="${i18n:_('Resource allocation')}" width="600px" closable="true" visible="false"> - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + +