diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/AdvanceTypeDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/AdvanceTypeDAO.java index d7003c2f0..173ac7f36 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/AdvanceTypeDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/AdvanceTypeDAO.java @@ -20,6 +20,7 @@ package org.navalplanner.business.advance.daos; +import java.util.Collection; import java.util.List; import org.hibernate.criterion.Restrictions; @@ -55,4 +56,9 @@ public class AdvanceTypeDAO extends GenericDAOHibernate return getSession().createCriteria(AdvanceType.class).add( Restrictions.eq("active", Boolean.TRUE)).list(); } + + @Override + public Collection getAll() { + return list(AdvanceType.class); + } } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/IAdvanceTypeDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/IAdvanceTypeDAO.java index 9f7143872..f701c7004 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/IAdvanceTypeDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/advance/daos/IAdvanceTypeDAO.java @@ -20,6 +20,7 @@ package org.navalplanner.business.advance.daos; +import java.util.Collection; import java.util.List; import org.navalplanner.business.advance.entities.AdvanceType; @@ -32,7 +33,11 @@ import org.navalplanner.business.common.daos.IGenericDAO; public interface IAdvanceTypeDAO extends IGenericDAO{ public boolean existsNameAdvanceType(String unitName); - public AdvanceType findByName(String name); + public List findActivesAdvanceTypes(); + public AdvanceType findByName(String name); + + public Collection getAll(); + } \ No newline at end of file diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/advance/entities/DirectAdvanceAssignment.java b/navalplanner-business/src/main/java/org/navalplanner/business/advance/entities/DirectAdvanceAssignment.java index 3bd4dfc93..6df433dec 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/advance/entities/DirectAdvanceAssignment.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/advance/entities/DirectAdvanceAssignment.java @@ -96,19 +96,6 @@ public class DirectAdvanceAssignment extends AdvanceAssignment { return advanceMeasurements.first(); } - public BigDecimal getAdvancePercentage() { - if (maxValue.compareTo(BigDecimal.ZERO) == 0) { - return BigDecimal.ZERO; - } - - AdvanceMeasurement advanceMeasurement = getLastAdvanceMeasurement(); - if (advanceMeasurement == null) { - return BigDecimal.ZERO; - } - return advanceMeasurement.getValue().setScale(2).divide(maxValue, - RoundingMode.DOWN); - } - public AdvanceMeasurement getAdvanceMeasurement(LocalDate date) { if (advanceMeasurements.isEmpty()) { return null; @@ -123,12 +110,17 @@ public class DirectAdvanceAssignment extends AdvanceAssignment { return null; } + public BigDecimal getAdvancePercentage() { + return getAdvancePercentage(null); + } + public BigDecimal getAdvancePercentage(LocalDate date) { if (maxValue.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } - AdvanceMeasurement advanceMeasurement = getAdvanceMeasurement(date); + AdvanceMeasurement advanceMeasurement = (date != null) ? getAdvanceMeasurement(date) + : getLastAdvanceMeasurement(); if (advanceMeasurement == null) { return BigDecimal.ZERO; } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java b/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java index 0be1975d7..b06d5b6e5 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/common/Registry.java @@ -31,6 +31,7 @@ import org.navalplanner.business.labels.daos.ILabelTypeDAO; import org.navalplanner.business.materials.daos.IMaterialCategoryDAO; import org.navalplanner.business.materials.daos.IMaterialDAO; import org.navalplanner.business.orders.daos.IHoursGroupDAO; +import org.navalplanner.business.orders.daos.IOrderDAO; import org.navalplanner.business.orders.daos.IOrderElementDAO; import org.navalplanner.business.qualityforms.daos.IQualityFormDAO; import org.navalplanner.business.resources.daos.ICriterionDAO; @@ -103,6 +104,9 @@ public class Registry { @Autowired private IProfileDAO profileDAO; + @Autowired + private IOrderDAO orderDAO; + @Autowired private IOrderElementDAO orderElementDAO; @@ -214,4 +218,8 @@ public class Registry { return getInstance().costCategoryDAO; } + public static IOrderDAO getOrderDAO() { + return getInstance().orderDAO; + } + } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java index caa36fc3e..c47ebc0d6 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/IOrderDAO.java @@ -26,11 +26,13 @@ import java.util.List; import org.navalplanner.business.common.daos.IGenericDAO; import org.navalplanner.business.orders.entities.Order; import org.navalplanner.business.reports.dtos.OrderCostsPerResourceDTO; +import org.navalplanner.business.planner.entities.Task; /** * Contract for {@link OrderDAO} * @author Óscar González Fernández * @author Lorenzo Tilve Álvaro + * @author Diego Pino Garcia */ public interface IOrderDAO extends IGenericDAO { @@ -43,9 +45,14 @@ public interface IOrderDAO extends IGenericDAO { /** * Builds contents for OrderCostsPerResource report * @return A {@link List} of {@link OrderCostsPerResourceDTO} objects for - * reporting + * reporting */ List getOrderCostsPerResource(List orders, Date startingDate, Date endingDate); + /* + * @param order + * @return + */ + List getTasksByOrder(Order order); } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java index cd59d8004..1f98e8395 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderDAO.java @@ -33,9 +33,11 @@ import org.navalplanner.business.costcategories.daos.CostCategoryDAO; import org.navalplanner.business.costcategories.daos.ITypeOfWorkHoursDAO; import org.navalplanner.business.costcategories.entities.TypeOfWorkHours; import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.orders.entities.OrderElement; import org.navalplanner.business.orders.entities.TaskSource; import org.navalplanner.business.planner.daos.ITaskSourceDAO; import org.navalplanner.business.reports.dtos.OrderCostsPerResourceDTO; +import org.navalplanner.business.planner.entities.Task; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; @@ -90,7 +92,6 @@ public class OrderDAO extends GenericDAOHibernate implements String orderStrQuery = "FROM Order order "; Query orderQuery = getSession().createQuery(orderStrQuery); List orderList = orderQuery.list(); - String strQuery = "SELECT new org.navalplanner.business.reports.dtos.OrderCostsPerResourceDTO(worker, wrl) " + "FROM Worker worker, WorkReportLine wrl " + "LEFT OUTER JOIN wrl.resource resource " @@ -111,6 +112,7 @@ public class OrderDAO extends GenericDAOHibernate implements strQuery += "ORDER BY worker.id, wrl.date"; Query query = getSession().createQuery(strQuery); + if (startingDate != null) { query.setParameter("startingDate", startingDate); } @@ -149,11 +151,27 @@ public class OrderDAO extends GenericDAOHibernate implements each.setCostPerHour(pricePerHour); each.setCost(each.getCostPerHour().multiply( new BigDecimal(each.getNumHours()))); - filteredList.add(each); } } return filteredList; } + @Override + public List getTasksByOrder(Order order) { + reattach(order); + List orderElements = order.getAllChildren(); + orderElements.add(order); + + final String strQuery = "SELECT taskSource.task " + + "FROM TaskSource taskSource " + + "WHERE taskSource.orderElement IN (:orderElements) " + + " AND taskSource.task IN (FROM Task)"; + + Query query = getSession().createQuery(strQuery); + query.setParameterList("orderElements", orderElements); + + return (List) query.list(); + } + } \ No newline at end of file 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 6945632df..7051d4652 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 @@ -348,6 +348,8 @@ public abstract class OrderElement extends BaseEntity implements public abstract DirectAdvanceAssignment getReportGlobalAdvanceAssignment(); + public abstract DirectAdvanceAssignment getAdvanceAssignmentByType(AdvanceType type); + public Set getDirectAdvanceAssignments() { return Collections.unmodifiableSet(directAdvanceAssignments); } @@ -942,4 +944,4 @@ public abstract class OrderElement extends BaseEntity implements return this; } -} \ No newline at end of file +} 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 828888500..aa7bc235b 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 @@ -501,6 +501,16 @@ public class OrderLine extends OrderElement { return null; } + @Override + public DirectAdvanceAssignment getAdvanceAssignmentByType(AdvanceType type) { + for (DirectAdvanceAssignment directAdvanceAssignment : getDirectAdvanceAssignments()) { + if (directAdvanceAssignment.getAdvanceType().equals(type)) { + return directAdvanceAssignment; + } + } + return null; + } + public void incrementLastHoursGroupSequenceCode() { if(lastHoursGroupSequenceCode==null){ lastHoursGroupSequenceCode = 0; @@ -524,7 +534,6 @@ public class OrderLine extends OrderElement { } codes.add(code); } - return true; } @@ -533,4 +542,4 @@ public class OrderLine extends OrderElement { return OrderLineTemplate.create(this); } -} \ No newline at end of file +} 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 295a6d6fe..91d02c86c 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 @@ -266,6 +266,14 @@ public class OrderLineGroup extends OrderElement implements return hoursGroups; } + public BigDecimal getAdvancePercentage(AdvanceType advanceType, LocalDate date) { + final DirectAdvanceAssignment directAdvanceAssignment = this.getAdvanceAssignmentByType(advanceType); + if (directAdvanceAssignment != null) { + return directAdvanceAssignment.getAdvancePercentage(date); + } + return null; + } + @Override public BigDecimal getAdvancePercentage(LocalDate date) { for (DirectAdvanceAssignment directAdvanceAssignment : directAdvanceAssignments) { @@ -762,6 +770,21 @@ public class OrderLineGroup extends OrderElement implements return null; } + public DirectAdvanceAssignment getAdvanceAssignmentByType(AdvanceType type) { + for (DirectAdvanceAssignment each : getDirectAdvanceAssignments()) { + if (type != null && each.getAdvanceType().getId().equals(type.getId())) { + return each; + } + } + + for (IndirectAdvanceAssignment each : getIndirectAdvanceAssignments()) { + if (type != null && each.getAdvanceType().getId().equals(type.getId())) { + return calculateFakeDirectAdvanceAssignment(each); + } + } + return null; + } + @Override public OrderElementTemplate createTemplate() { return OrderLineGroupTemplate.create(this); diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/reports/dtos/SchedulingProgressPerOrderDTO.java b/navalplanner-business/src/main/java/org/navalplanner/business/reports/dtos/SchedulingProgressPerOrderDTO.java new file mode 100644 index 000000000..6d06f064a --- /dev/null +++ b/navalplanner-business/src/main/java/org/navalplanner/business/reports/dtos/SchedulingProgressPerOrderDTO.java @@ -0,0 +1,285 @@ +/* + * 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.reports.dtos; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.util.ArrayList; +import java.util.List; + +import org.joda.time.LocalDate; +import org.navalplanner.business.advance.entities.AdvanceType; +import org.navalplanner.business.advance.entities.DirectAdvanceAssignment; +import org.navalplanner.business.common.Registry; +import org.navalplanner.business.orders.daos.IOrderDAO; +import org.navalplanner.business.orders.entities.Order; +import org.navalplanner.business.planner.entities.DayAssignment; +import org.navalplanner.business.planner.entities.Task; +import org.navalplanner.business.planner.entities.TaskElement; +import org.navalplanner.business.workreports.daos.IWorkReportLineDAO; +import org.navalplanner.business.workreports.entities.WorkReportLine; + +/** + * + * @author Diego Pino Garcia + * + */ +public class SchedulingProgressPerOrderDTO { + + private IOrderDAO orderDAO; + + private IWorkReportLineDAO workReportLineDAO; + + private String orderName; + + private Integer estimatedHours; + + private Integer totalPlannedHours; + + private Integer partialPlannedHours; + + private Integer realHours; + + private BigDecimal averageProgress; + + private Double imputedProgress; + + private Double plannedProgress; + + private BigDecimal costDifference; + + private BigDecimal planningDifference; + + private BigDecimal ratioCostDifference; + + private BigDecimal ratioPlanningDifference; + + private Boolean advanceTypeDoesNotApply = Boolean.FALSE; + + private SchedulingProgressPerOrderDTO() { + workReportLineDAO = Registry.getWorkReportLineDAO(); + orderDAO = Registry.getOrderDAO(); + } + + public SchedulingProgressPerOrderDTO(Order order, AdvanceType advanceType, LocalDate date) { + this(); + this.orderName = order.getName(); + + // Get average progress + if (advanceType != null) { + averageProgress = order.getAdvancePercentage(advanceType, date); + } else { + final DirectAdvanceAssignment directAdvanceAssignment = order.getReportGlobalAdvanceAssignment(); + averageProgress = (directAdvanceAssignment != null) ? directAdvanceAssignment.getAdvancePercentage(date) : null; + } + + if (averageProgress == null) { + advanceTypeDoesNotApply = true; + averageProgress = new BigDecimal(0); + } + + // Fill DTO + + // Total hours calculations + final List tasks = orderDAO.getTasksByOrder(order); + + getTasks(order); + this.estimatedHours = getHoursSpecifiedAtOrder(tasks); + this.totalPlannedHours = calculatePlannedHours(tasks, null); + + // Hours on time calculations + this.partialPlannedHours = calculatePlannedHours(tasks, date); + this.realHours = calculateRealHours(tasks, date); + + // Progress calculations + this.imputedProgress = (totalPlannedHours != 0) ? new Double(realHours + / totalPlannedHours.doubleValue()) : new Double(0); + this.plannedProgress = (totalPlannedHours != 0) ? new Double( + partialPlannedHours / totalPlannedHours.doubleValue()) + : new Double(0); + + // Differences calculations + this.costDifference = calculateCostDifference(averageProgress, + new BigDecimal(totalPlannedHours), new BigDecimal(realHours)); + this.planningDifference = calculatePlanningDifference(averageProgress, + new BigDecimal(totalPlannedHours), new BigDecimal( + partialPlannedHours)); + this.ratioCostDifference = calculateRatioCostDifference( + averageProgress, imputedProgress); + this.ratioPlanningDifference = calculateRatioPlanningDifference( + averageProgress, plannedProgress); + } + + private List getTasks(Order order) { + List result = new ArrayList(); + + final List taskElements = order + .getAllChildrenAssociatedTaskElements(); + for (TaskElement each : taskElements) { + if (each instanceof Task) { + result.add((Task) each); + } + } + return result; + } + + private Integer getHoursSpecifiedAtOrder(List tasks) { + Integer result = new Integer(0); + + for (Task each: tasks) { + result += each.getHoursSpecifiedAtOrder(); + } + return result; + } + + public Integer calculatePlannedHours(List tasks, LocalDate date) { + Integer result = new Integer(0); + + for (Task each: tasks) { + result += calculatePlannedHours(each, date); + } + return result; + } + + public Integer calculatePlannedHours(Task task, LocalDate date) { + Integer result = new Integer(0); + + final List dayAssignments = task.getDayAssignments(); + if (dayAssignments.isEmpty()) { + return result; + } + + for (DayAssignment dayAssignment : dayAssignments) { + if (date == null || dayAssignment.getDay().compareTo(date) <= 0) { + result += dayAssignment.getHours(); + } + } + return result; + } + + public Integer calculateRealHours(List tasks, LocalDate date) { + Integer result = new Integer(0); + + for (Task each: tasks) { + result += calculateRealHours(each, date); + } + return result; + } + + public Integer calculateRealHours(Task task, LocalDate date) { + Integer result = new Integer(0); + + final List workReportLines = workReportLineDAO + .findByOrderElementAndChildren(task.getOrderElement()); + if (workReportLines.isEmpty()) { + return result; + } + + for (WorkReportLine workReportLine : workReportLines) { + final LocalDate workReportLineDate = new LocalDate(workReportLine.getDate()); + if (date == null || workReportLineDate.compareTo(date) <= 0) { + result += workReportLine.getNumHours(); + } + } + return result; + } + + public Integer getEstimatedHours() { + return estimatedHours; + } + + public Integer getTotalPlannedHours() { + return totalPlannedHours; + } + + public Integer getPartialPlannedHours() { + return partialPlannedHours; + } + + public Integer getRealHours() { + return realHours; + } + + public BigDecimal getAverageProgress() { + return averageProgress; + } + + public Double getImputedProgress() { + return imputedProgress; + } + + public Double getPlannedProgress() { + return plannedProgress; + } + + public String getOrderName() { + return orderName; + } + + public BigDecimal calculateCostDifference(BigDecimal averageProgress, + BigDecimal totalPlannedHours, BigDecimal realHours) { + BigDecimal result = averageProgress; + result = result.multiply(totalPlannedHours); + return result.subtract(realHours); + } + + public BigDecimal calculatePlanningDifference(BigDecimal averageProgress, + BigDecimal totalPlannedHours, BigDecimal partialPlannedHours) { + BigDecimal result = averageProgress; + result = result.multiply(totalPlannedHours); + return result.subtract(partialPlannedHours); + } + + public BigDecimal calculateRatioCostDifference(BigDecimal averageProgress, Double imputedProgress) { + if (imputedProgress.doubleValue() == 0) { + return new BigDecimal(0); + } + return averageProgress.divide(new BigDecimal(imputedProgress), 2, RoundingMode.HALF_UP); + } + + public BigDecimal calculateRatioPlanningDifference(BigDecimal averageProgress, Double plannedProgress) { + if (plannedProgress.doubleValue() == 0) { + return new BigDecimal(0); + } + return averageProgress.divide(new BigDecimal(plannedProgress), 2, RoundingMode.HALF_UP); + } + + public BigDecimal getCostDifference() { + return costDifference; + } + + public BigDecimal getPlanningDifference() { + return planningDifference; + } + + public BigDecimal getRatioCostDifference() { + return ratioCostDifference; + } + + public BigDecimal getRatioPlanningDifference() { + return ratioPlanningDifference; + } + + public Boolean getAdvanceTypeDoesNotApply() { + return advanceTypeDoesNotApply; + } + +} diff --git a/navalplanner-webapp/src/main/jasper/schedulingProgressPerOrderReport.jrxml b/navalplanner-webapp/src/main/jasper/schedulingProgressPerOrderReport.jrxml new file mode 100644 index 000000000..6e481acc7 --- /dev/null +++ b/navalplanner-webapp/src/main/jasper/schedulingProgressPerOrderReport.jrxml @@ -0,0 +1,535 @@ + + +