diff --git a/libreplan-business/src/main/java/org/libreplan/business/workreports/entities/WorkReport.java b/libreplan-business/src/main/java/org/libreplan/business/workreports/entities/WorkReport.java index 866a43ea4..7061003a7 100644 --- a/libreplan-business/src/main/java/org/libreplan/business/workreports/entities/WorkReport.java +++ b/libreplan-business/src/main/java/org/libreplan/business/workreports/entities/WorkReport.java @@ -3,7 +3,7 @@ * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia - * Copyright (C) 2010-2011 Igalia, S.L. + * Copyright (C) 2010-2012 Igalia, S.L. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -39,6 +39,7 @@ import org.libreplan.business.labels.entities.Label; import org.libreplan.business.labels.entities.LabelType; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.resources.entities.Resource; +import org.libreplan.business.workingday.EffortDuration; import org.libreplan.business.workreports.daos.IWorkReportDAO; import org.libreplan.business.workreports.valueobjects.DescriptionField; import org.libreplan.business.workreports.valueobjects.DescriptionValue; @@ -46,6 +47,7 @@ import org.libreplan.business.workreports.valueobjects.DescriptionValue; /** * @author Diego Pino García * @author Susana Montes Pedreira + * @author Manuel Rego Casasnovas */ public class WorkReport extends IntegrationEntity implements IWorkReportsElements { @@ -455,4 +457,12 @@ public class WorkReport extends IntegrationEntity implements return lastWorkReportLineSequenceCode; } + public EffortDuration getTotalEffortDuration() { + EffortDuration result = EffortDuration.zero(); + for (WorkReportLine line : workReportLines) { + result = result.plus(line.getEffort()); + } + return result; + } + } diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/IMonthlyTimesheetModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/IMonthlyTimesheetModel.java index 43a32d68d..b8931d824 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/IMonthlyTimesheetModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/IMonthlyTimesheetModel.java @@ -82,4 +82,17 @@ public interface IMonthlyTimesheetModel { */ EffortDuration getEffortDuration(OrderElement orderElement); + /** + * Returns the {@link EffortDuration} for all the {@link OrderElement + * OrderElements} in the current monthly timesheet in the specified + * date. + */ + EffortDuration getEffortDuration(LocalDate date); + + /** + * Returns the total {@link EffortDuration} for the currently monthly + * timesheet. + */ + EffortDuration getTotalEffortDuration(); + } \ No newline at end of file diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetController.java b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetController.java index bea512eb1..75e7d9806 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetController.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetController.java @@ -22,6 +22,7 @@ package org.libreplan.web.users.dashboard; import static org.libreplan.web.I18nHelper._; import static org.libreplan.web.planner.tabs.MultipleTabsPlannerController.BREADCRUMBS_SEPARATOR; +import java.util.ArrayList; import java.util.List; import org.joda.time.LocalDate; @@ -30,10 +31,12 @@ import org.libreplan.business.workingday.EffortDuration; import org.libreplan.web.common.Util; import org.libreplan.web.common.entrypoints.IURLHandlerRegistry; import org.libreplan.web.users.services.CustomTargetUrlResolver; +import org.springframework.util.Assert; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.Executions; import org.zkoss.zk.ui.WrongValueException; import org.zkoss.zk.ui.util.GenericForwardComposer; +import org.zkoss.zul.Cell; import org.zkoss.zul.Column; import org.zkoss.zul.Columns; import org.zkoss.zul.Image; @@ -52,6 +55,8 @@ import org.zkoss.zul.api.Grid; public class MonthlyTimesheetController extends GenericForwardComposer implements IMonthlyTimesheetController { + private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px"; + private IMonthlyTimesheetModel monthlyTimesheetModel; private IURLHandlerRegistry URLHandlerRegistry; @@ -60,13 +65,42 @@ public class MonthlyTimesheetController extends GenericForwardComposer private Columns columns; - private RowRenderer orderElementsRenderer = new RowRenderer() { + private RowRenderer rowRenderer = new RowRenderer() { + + private LocalDate start; + private LocalDate end; @Override public void render(Row row, Object data) throws Exception { - OrderElement orderElement = (OrderElement) data; - row.setValue(orderElement); + MonthlyTimesheetRow monthlyTimesheetRow = (MonthlyTimesheetRow) data; + initMonthlyTimesheetDates(); + + switch (monthlyTimesheetRow.getType()) { + case ORDER_ELEMENT: + renderOrderElementRow(row, + monthlyTimesheetRow.getOrderElemement()); + break; + case CAPACITY: + // TODO + break; + case TOTAL: + renderTotalRow(row); + break; + default: + throw new IllegalStateException( + "Unknown MonthlyTimesheetRow type: " + + monthlyTimesheetRow.getType()); + } + } + + private void initMonthlyTimesheetDates() { + LocalDate date = monthlyTimesheetModel.getDate(); + start = date.dayOfMonth().withMinimumValue(); + end = date.dayOfMonth().withMaximumValue(); + } + + private void renderOrderElementRow(Row row, OrderElement orderElement) { Util.appendLabel(row, orderElement.getOrder().getName()); Util.appendLabel(row, orderElement.getName()); @@ -77,17 +111,12 @@ public class MonthlyTimesheetController extends GenericForwardComposer private void appendInputsForDays(Row row, final OrderElement orderElement) { - LocalDate date = monthlyTimesheetModel.getDate(); - - LocalDate start = date.dayOfMonth().withMinimumValue(); - LocalDate end = date.dayOfMonth().withMaximumValue(); - for (LocalDate day = start; day.compareTo(end) <= 0; day = day .plusDays(1)) { final LocalDate textboxDate = day; final Textbox textbox = new Textbox(); - textbox.setWidth("30px"); + textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH); Util.bind(textbox, new Util.Getter() { @Override @@ -108,7 +137,14 @@ public class MonthlyTimesheetController extends GenericForwardComposer } monthlyTimesheetModel.setEffortDuration(orderElement, textboxDate, effortDuration); + updateTotals(orderElement, textboxDate); + } + + private void updateTotals(OrderElement orderElement, + LocalDate date) { updateTotalColumn(orderElement); + updateTotalRow(date); + updateTotalColumn(); } }); @@ -120,6 +156,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer private void appendTotalColumn(Row row, final OrderElement orderElement) { Textbox textbox = new Textbox(); + textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH); textbox.setId(getTotalColumnTextboxId(orderElement)); textbox.setDisabled(true); row.appendChild(textbox); @@ -137,6 +174,65 @@ public class MonthlyTimesheetController extends GenericForwardComposer orderElement).toFormattedString()); } + private void renderTotalRow(Row row) { + appendTotalLabel(row); + appendTotalForDays(row); + appendTotalColumn(row); + } + + private void appendTotalLabel(Row row) { + Label label = new Label(_("Total")); + Cell cell = new Cell(); + cell.setColspan(2); + cell.appendChild(label); + row.appendChild(cell); + } + + private void appendTotalForDays(Row row) { + for (LocalDate day = start; day.compareTo(end) <= 0; day = day + .plusDays(1)) { + Textbox textbox = new Textbox(); + textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH); + textbox.setId(getTotalRowTextboxId(day)); + textbox.setDisabled(true); + row.appendChild(textbox); + + updateTotalRow(day); + } + } + + private String getTotalRowTextboxId(LocalDate date) { + return "textbox-total-row-" + date; + } + + private void updateTotalRow(LocalDate date) { + Textbox textbox = (Textbox) timesheet + .getFellow(getTotalRowTextboxId(date)); + textbox.setValue(monthlyTimesheetModel.getEffortDuration(date) + .toFormattedString()); + } + + private void appendTotalColumn(Row row) { + Textbox textbox = new Textbox(); + textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH); + textbox.setId(getTotalTextboxId()); + textbox.setDisabled(true); + row.appendChild(textbox); + + updateTotalColumn(); + } + + private String getTotalTextboxId() { + return "textbox-total"; + } + + private void updateTotalColumn() { + Textbox textbox = (Textbox) timesheet + .getFellow(getTotalTextboxId()); + textbox.setValue(monthlyTimesheetModel.getTotalEffortDuration() + .toFormattedString()); + } + }; @Override @@ -210,12 +306,16 @@ public class MonthlyTimesheetController extends GenericForwardComposer return monthlyTimesheetModel.getWorker().getShortDescription(); } - public List getOrderElements() { - return monthlyTimesheetModel.getOrderElements(); + public List getRows() { + List result = MonthlyTimesheetRow + .wrap(monthlyTimesheetModel + .getOrderElements()); + result.add(MonthlyTimesheetRow.createTotalRow()); + return result; } - public RowRenderer getOrderElementsRenderer() { - return orderElementsRenderer; + public RowRenderer getRowRenderer() { + return rowRenderer; } public void save() { @@ -232,3 +332,56 @@ public class MonthlyTimesheetController extends GenericForwardComposer } } + +/** + * Simple class to represent the the rows in the monthly timesheet grid.
+ * + * This is used to mark the special rows like capacity and total. + */ +class MonthlyTimesheetRow { + enum MonthlyTimesheetRowType { + ORDER_ELEMENT, CAPACITY, TOTAL + }; + + private MonthlyTimesheetRowType type; + private OrderElement orderElemement; + + public static MonthlyTimesheetRow createOrderElementRow( + OrderElement orderElemement) { + MonthlyTimesheetRow row = new MonthlyTimesheetRow( + MonthlyTimesheetRowType.ORDER_ELEMENT); + Assert.notNull(orderElemement); + row.orderElemement = orderElemement; + return row; + } + + public static MonthlyTimesheetRow createCapacityRow() { + return new MonthlyTimesheetRow(MonthlyTimesheetRowType.CAPACITY); + } + + public static MonthlyTimesheetRow createTotalRow() { + return new MonthlyTimesheetRow(MonthlyTimesheetRowType.TOTAL); + } + + public static List wrap( + List orderElements) { + List result = new ArrayList(); + for (OrderElement each : orderElements) { + result.add(createOrderElementRow(each)); + } + return result; + } + + private MonthlyTimesheetRow(MonthlyTimesheetRowType type) { + this.type = type; + } + + public MonthlyTimesheetRowType getType() { + return type; + } + + public OrderElement getOrderElemement() { + return orderElemement; + } + +} diff --git a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetModel.java b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetModel.java index c7949b875..aa69d0c28 100644 --- a/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetModel.java +++ b/libreplan-webapp/src/main/java/org/libreplan/web/users/dashboard/MonthlyTimesheetModel.java @@ -244,4 +244,20 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel { return result; } + @Override + public EffortDuration getEffortDuration(LocalDate date) { + EffortDuration result = EffortDuration.zero(); + for (WorkReportLine line : workReport.getWorkReportLines()) { + if (LocalDate.fromDateFields(line.getDate()).equals(date)) { + result = result.plus(line.getEffort()); + } + } + return result; + } + + @Override + public EffortDuration getTotalEffortDuration() { + return workReport.getTotalEffortDuration(); + } + } diff --git a/libreplan-webapp/src/main/webapp/myaccount/monthlyTimesheet.zul b/libreplan-webapp/src/main/webapp/myaccount/monthlyTimesheet.zul index a63b7d150..805431337 100644 --- a/libreplan-webapp/src/main/webapp/myaccount/monthlyTimesheet.zul +++ b/libreplan-webapp/src/main/webapp/myaccount/monthlyTimesheet.zul @@ -53,8 +53,8 @@ + model="@{controller.rows}" + rowRenderer="@{controller.rowRenderer}" />