From 949ad8f0bc05cfad96f04b4b50eb3b9da63a0d66 Mon Sep 17 00:00:00 2001 From: Susana Montes Pedreira Date: Tue, 26 Jan 2010 22:56:47 +0100 Subject: [PATCH] ItEr45S12RFGravacionDatosHistoricosResponsabilidadesTraballoUnidadesPlanItEr44S18: historical statistics of the templates. --- .../business/orders/daos/OrderElementDAO.java | 8 +- .../templates/OrderTemplatesController.java | 8 + ...rElementHistoricalStatisticsComponent.java | 299 ++++++++++++++++++ .../templates/_historicalStatistics.zul | 67 ++++ .../src/main/webapp/templates/templates.zul | 5 + 5 files changed, 385 insertions(+), 2 deletions(-) create mode 100644 navalplanner-webapp/src/main/java/org/navalplanner/web/templates/historicalStatistics/OrderElementHistoricalStatisticsComponent.java create mode 100644 navalplanner-webapp/src/main/webapp/templates/_historicalStatistics.zul diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java index f36cc2df9..dd881c80d 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java @@ -113,7 +113,7 @@ public class OrderElementDAO extends GenericDAOHibernate OrderElement order = transactionService .runOnAnotherTransaction(new IOnTransaction() { - @Override + @Override public OrderElement execute() { OrderElement current = orderElement; OrderElement result = current; @@ -124,7 +124,11 @@ public class OrderElementDAO extends GenericDAOHibernate return result; } }); - return orderDAO.findExistingEntity(order.getId()); + if (order != null) { + return orderDAO.findExistingEntity(order.getId()); + } else { + return null; + } } @Override diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/OrderTemplatesController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/OrderTemplatesController.java index 16f79f92e..c7fefb451 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/OrderTemplatesController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/OrderTemplatesController.java @@ -32,6 +32,7 @@ import org.navalplanner.web.common.entrypoints.URLHandler; import org.navalplanner.web.planner.tabs.IGlobalViewEntryPoints; import org.navalplanner.web.templates.advances.AdvancesAssignmentComponent; import org.navalplanner.web.templates.historicalAssignment.OrderElementHistoricalAssignmentComponent; +import org.navalplanner.web.templates.historicalStatistics.OrderElementHistoricalStatisticsComponent; import org.navalplanner.web.templates.labels.LabelsAssignmentToTemplateComponent; import org.navalplanner.web.templates.materials.MaterialAssignmentTemplateComponent; import org.navalplanner.web.templates.quality.QualityFormAssignerComponent; @@ -102,6 +103,7 @@ public class OrderTemplatesController extends GenericForwardComposer implements bindQualityFormWithCurrentTemplate(); bindEditTemplateWindowWithController(); bindHistoricalArragenmentWithCurrentTemplate(); + bindHistoricalStatisticsWithCurrentTemplate(); show(editWindow); } @@ -149,6 +151,12 @@ public class OrderTemplatesController extends GenericForwardComposer implements c.useModel(model, globalView); } + private void bindHistoricalStatisticsWithCurrentTemplate() { + OrderElementHistoricalStatisticsComponent c = (OrderElementHistoricalStatisticsComponent) editWindow + .getFellow("historicalStatistics"); + c.useModel(model); + } + public boolean isTemplateTreeDisabled() { return model.isTemplateTreeDisabled(); } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/historicalStatistics/OrderElementHistoricalStatisticsComponent.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/historicalStatistics/OrderElementHistoricalStatisticsComponent.java new file mode 100644 index 000000000..f76339b79 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/templates/historicalStatistics/OrderElementHistoricalStatisticsComponent.java @@ -0,0 +1,299 @@ +/* + * 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.web.templates.historicalStatistics; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; + +import org.navalplanner.business.common.IAdHocTransactionService; +import org.navalplanner.business.common.IOnTransaction; +import org.navalplanner.business.orders.daos.IOrderElementDAO; +import org.navalplanner.business.orders.entities.OrderElement; +import org.navalplanner.business.planner.entities.TaskElement; +import org.navalplanner.business.templates.entities.OrderElementTemplate; +import org.navalplanner.web.templates.IOrderTemplatesModel; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.WebApplicationContextUtils; +import org.zkoss.zk.ui.Executions; +import org.zkoss.zk.ui.HtmlMacroComponent; + +/** + * @author Susana Montes Pedreira + */ + +public class OrderElementHistoricalStatisticsComponent extends + HtmlMacroComponent { + + private OrderElementTemplate template; + + private IOrderTemplatesModel model; + + private IAdHocTransactionService adHocTransactionService; + + private IOrderElementDAO orderElementDAO; + + private List orderElements = new ArrayList(); + + public String applications = "0"; + public String finishApplications = "0"; + public String averageEstimatedHours = "0"; + public String averageWorkedHours = "0"; + public String differentialEstimatedHours = "0"; + public String differentialWorkedHours = "0"; + + @Transactional(readOnly = true) + public void afterCompose() { + super.afterCompose(); + this.adHocTransactionService = (IAdHocTransactionService) getBean("adHocTransactionService"); + this.orderElementDAO = (IOrderElementDAO) getBean("orderElementDAO"); + } + + public void useModel(IOrderTemplatesModel model) { + template = model.getTemplate(); + this.model = model; + calculateTemplateHistoricalStatistics(); + } + + @Transactional(readOnly = true) + public void calculateTemplateHistoricalStatistics() { + if ((model != null) && (template != null) && (!template.isNewObject())) { + this.adHocTransactionService + .runOnReadOnlyTransaction(new IOnTransaction() { + @Override + public Void execute() { + orderElements = getOrderElementsWithThisAssignedTemplate(); + applications = getApplicationsNumber().toString(); + finishApplications = getFinishedApplicationsNumber() + .toString(); + averageEstimatedHours = calculateAverageEstimatedHours() + .toString(); + averageWorkedHours = calculateAverageWorkedHours() + .toString(); + differentialEstimatedHours = calculateEstimatedDifferential() + .toString(); + differentialWorkedHours = calculateWorkedDifferential() + .toString(); + return null; + } + }); + } + } + + public List getOrderElementsWithThisAssignedTemplate() { + orderElements.clear(); + if ((model != null) && (template != null) && (!template.isNewObject())) { + orderElements.addAll(orderElementDAO.findByTemplate(template)); + } + return orderElements; + } + + public String getApplications() { + return applications; + } + + public String getFinishApplications() { + return finishApplications; + } + + public String getAverageEstimatedHours() { + return averageEstimatedHours; + } + + public String getAverageWorkedHours() { + return averageWorkedHours; + } + + public String getDifferentialEstimatedHours() { + return differentialEstimatedHours; + } + + public String getDifferentialWorkedHours() { + return differentialWorkedHours; + } + + /** + * Operations to calculate the historical statistics of the current template + */ + + public Integer getApplicationsNumber() { + return orderElements.size(); + } + + public Integer getFinishedApplicationsNumber() { + return getFinishedApplications().size(); + } + + public BigDecimal calculateAverageEstimatedHours() { + BigDecimal sum = new BigDecimal(0); + BigDecimal average = new BigDecimal(0); + final List list = getFinishedApplications(); + + for (OrderElement orderElement : list) { + sum = sum.add(new BigDecimal(orderElement.getWorkHours())); + } + if (sum.compareTo(new BigDecimal(0)) > 0) { + average = sum.divide(new BigDecimal(list.size())); + } + return average; + } + + public BigDecimal calculateAverageWorkedHours() { + BigDecimal sum = new BigDecimal(0); + BigDecimal average = new BigDecimal(0); + final List list = getFinishedApplications(); + + for (OrderElement orderElement : list) { + sum = sum.add(new BigDecimal(orderElementDAO + .getAssignedDirectHours(orderElement))); + } + if (sum.compareTo(new BigDecimal(0)) > 0) { + average = sum.divide(new BigDecimal(list.size())); + } + return average; + } + + public BigDecimal calculateEstimatedDifferential() { + BigDecimal average = new BigDecimal(0); + final List list = getFinishedApplications(); + if (!list.isEmpty()) { + BigDecimal initValue = new BigDecimal(list.get(0).getWorkHours()); + BigDecimal max = initValue.setScale(2); + BigDecimal min = initValue.setScale(2); + + for (OrderElement orderElement : list) { + BigDecimal value = new BigDecimal(orderElement.getWorkHours()); + if (max.compareTo(value) < 0) { + max = value.setScale(2); + } + if (min.compareTo(value) > 0) { + min = value.setScale(2); + } + } + if (max.compareTo(new BigDecimal(0)) > 0) { + average = max.divide(min).setScale(2); + } + } + return average; + } + + public BigDecimal calculateWorkedDifferential() { + BigDecimal average = new BigDecimal(0); + final List list = getFinishedApplications(); + if (!list.isEmpty()) { + BigDecimal initValue = new BigDecimal(orderElementDAO + .getAssignedDirectHours(list.get(0))); + BigDecimal max = initValue.setScale(2); + BigDecimal min = initValue.setScale(2); + + for (OrderElement orderElement : list) { + BigDecimal value = new BigDecimal(orderElementDAO + .getAssignedDirectHours(orderElement)); + if (max.compareTo(value) < 0) { + max = value.setScale(2); + } + if (min.compareTo(value) > 0) { + min = value.setScale(2); + } + } + if (max.compareTo(new BigDecimal(0)) > 0) { + average = max.divide(min).setScale(2); + } + } + return average; + } + + private List getFinishedApplications() { + List result = new ArrayList(); + for (OrderElement orderElement : orderElements) { + if (isFinishApplication(orderElement)) { + result.add(orderElement); + } + } + return result; + } + + private boolean isFinishApplication(OrderElement orderElement) { + // look up into the order elements tree + TaskElement task = lookToUpAssignedTask(orderElement); + if (task != null) { + return isFinished(task.getOrderElement()); + } + // look down into the order elements tree + List listTask = lookToDownAssignedTask(orderElement); + if (!listTask.isEmpty()) { + for (TaskElement taskElement : listTask) { + if (!isFinished(taskElement.getOrderElement())) { + return false; + } + } + } + // not exist assigned task + return isFinished(orderElementDAO + .loadOrderAvoidingProxyFor(orderElement)); + } + + private TaskElement lookToUpAssignedTask(OrderElement current) { + OrderElement result = current; + while (current != null) { + if (current.isSchedulingPoint()) { + return current.getAssociatedTaskElement(); + } + result = current; + current = current.getParent(); + } + return null; + } + + private List lookToDownAssignedTask(OrderElement current) { + List resultTask = new ArrayList(); + for (OrderElement child : current.getAllChildren()) { + if (child.isSchedulingPoint()) { + TaskElement task = child.getAssociatedTaskElement(); + if (task != null) { + resultTask.add(task); + } + } + } + return resultTask; + } + + private boolean isFinished(OrderElement orderElement) { + BigDecimal measuredProgress = orderElement.getAdvancePercentage(); + measuredProgress = (measuredProgress.setScale(0, BigDecimal.ROUND_UP) + .multiply(new BigDecimal(100))); + return (measuredProgress.compareTo(new BigDecimal(100)) == 0); + } + + private Object getBean(String classname) { + HttpServletRequest servletRequest = (HttpServletRequest) Executions + .getCurrent().getNativeRequest(); + ServletContext servletContext = servletRequest.getSession() + .getServletContext(); + WebApplicationContext webApplicationContext = WebApplicationContextUtils + .getWebApplicationContext(servletContext); + return webApplicationContext.getBean(classname); + } +} \ No newline at end of file diff --git a/navalplanner-webapp/src/main/webapp/templates/_historicalStatistics.zul b/navalplanner-webapp/src/main/webapp/templates/_historicalStatistics.zul new file mode 100644 index 000000000..4ccb5b4bc --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/templates/_historicalStatistics.zul @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/navalplanner-webapp/src/main/webapp/templates/templates.zul b/navalplanner-webapp/src/main/webapp/templates/templates.zul index 210c72286..448e610c4 100644 --- a/navalplanner-webapp/src/main/webapp/templates/templates.zul +++ b/navalplanner-webapp/src/main/webapp/templates/templates.zul @@ -36,6 +36,7 @@ + + @@ -106,6 +108,9 @@ + + +