Add total row to monthly timesheets
Create a new class MonthlyTimesheetRow to manage this kind of special like total or capacity in the future. FEA: ItEr76S28UserDashboard
This commit is contained in:
parent
79eb53d6f0
commit
346214c2ce
5 changed files with 208 additions and 16 deletions
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||||
* Desenvolvemento Tecnolóxico de Galicia
|
* 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
|
* 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
|
* 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.labels.entities.LabelType;
|
||||||
import org.libreplan.business.orders.entities.OrderElement;
|
import org.libreplan.business.orders.entities.OrderElement;
|
||||||
import org.libreplan.business.resources.entities.Resource;
|
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.daos.IWorkReportDAO;
|
||||||
import org.libreplan.business.workreports.valueobjects.DescriptionField;
|
import org.libreplan.business.workreports.valueobjects.DescriptionField;
|
||||||
import org.libreplan.business.workreports.valueobjects.DescriptionValue;
|
import org.libreplan.business.workreports.valueobjects.DescriptionValue;
|
||||||
|
|
@ -46,6 +47,7 @@ import org.libreplan.business.workreports.valueobjects.DescriptionValue;
|
||||||
/**
|
/**
|
||||||
* @author Diego Pino García <dpino@igalia.com>
|
* @author Diego Pino García <dpino@igalia.com>
|
||||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||||
|
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||||
*/
|
*/
|
||||||
public class WorkReport extends IntegrationEntity implements
|
public class WorkReport extends IntegrationEntity implements
|
||||||
IWorkReportsElements {
|
IWorkReportsElements {
|
||||||
|
|
@ -455,4 +457,12 @@ public class WorkReport extends IntegrationEntity implements
|
||||||
return lastWorkReportLineSequenceCode;
|
return lastWorkReportLineSequenceCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EffortDuration getTotalEffortDuration() {
|
||||||
|
EffortDuration result = EffortDuration.zero();
|
||||||
|
for (WorkReportLine line : workReportLines) {
|
||||||
|
result = result.plus(line.getEffort());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -82,4 +82,17 @@ public interface IMonthlyTimesheetModel {
|
||||||
*/
|
*/
|
||||||
EffortDuration getEffortDuration(OrderElement orderElement);
|
EffortDuration getEffortDuration(OrderElement orderElement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link EffortDuration} for all the {@link OrderElement
|
||||||
|
* OrderElements} in the current monthly timesheet in the specified
|
||||||
|
* <code>date</code>.
|
||||||
|
*/
|
||||||
|
EffortDuration getEffortDuration(LocalDate date);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the total {@link EffortDuration} for the currently monthly
|
||||||
|
* timesheet.
|
||||||
|
*/
|
||||||
|
EffortDuration getTotalEffortDuration();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -22,6 +22,7 @@ package org.libreplan.web.users.dashboard;
|
||||||
import static org.libreplan.web.I18nHelper._;
|
import static org.libreplan.web.I18nHelper._;
|
||||||
import static org.libreplan.web.planner.tabs.MultipleTabsPlannerController.BREADCRUMBS_SEPARATOR;
|
import static org.libreplan.web.planner.tabs.MultipleTabsPlannerController.BREADCRUMBS_SEPARATOR;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.joda.time.LocalDate;
|
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.Util;
|
||||||
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
|
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
|
||||||
import org.libreplan.web.users.services.CustomTargetUrlResolver;
|
import org.libreplan.web.users.services.CustomTargetUrlResolver;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
import org.zkoss.zk.ui.Component;
|
import org.zkoss.zk.ui.Component;
|
||||||
import org.zkoss.zk.ui.Executions;
|
import org.zkoss.zk.ui.Executions;
|
||||||
import org.zkoss.zk.ui.WrongValueException;
|
import org.zkoss.zk.ui.WrongValueException;
|
||||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||||
|
import org.zkoss.zul.Cell;
|
||||||
import org.zkoss.zul.Column;
|
import org.zkoss.zul.Column;
|
||||||
import org.zkoss.zul.Columns;
|
import org.zkoss.zul.Columns;
|
||||||
import org.zkoss.zul.Image;
|
import org.zkoss.zul.Image;
|
||||||
|
|
@ -52,6 +55,8 @@ import org.zkoss.zul.api.Grid;
|
||||||
public class MonthlyTimesheetController extends GenericForwardComposer
|
public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
implements IMonthlyTimesheetController {
|
implements IMonthlyTimesheetController {
|
||||||
|
|
||||||
|
private final static String EFFORT_DURATION_TEXTBOX_WIDTH = "30px";
|
||||||
|
|
||||||
private IMonthlyTimesheetModel monthlyTimesheetModel;
|
private IMonthlyTimesheetModel monthlyTimesheetModel;
|
||||||
|
|
||||||
private IURLHandlerRegistry URLHandlerRegistry;
|
private IURLHandlerRegistry URLHandlerRegistry;
|
||||||
|
|
@ -60,13 +65,42 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
|
|
||||||
private Columns columns;
|
private Columns columns;
|
||||||
|
|
||||||
private RowRenderer orderElementsRenderer = new RowRenderer() {
|
private RowRenderer rowRenderer = new RowRenderer() {
|
||||||
|
|
||||||
|
private LocalDate start;
|
||||||
|
private LocalDate end;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void render(Row row, Object data) throws Exception {
|
public void render(Row row, Object data) throws Exception {
|
||||||
OrderElement orderElement = (OrderElement) data;
|
MonthlyTimesheetRow monthlyTimesheetRow = (MonthlyTimesheetRow) data;
|
||||||
row.setValue(orderElement);
|
|
||||||
|
|
||||||
|
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.getOrder().getName());
|
||||||
Util.appendLabel(row, orderElement.getName());
|
Util.appendLabel(row, orderElement.getName());
|
||||||
|
|
||||||
|
|
@ -77,17 +111,12 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
|
|
||||||
private void appendInputsForDays(Row row,
|
private void appendInputsForDays(Row row,
|
||||||
final OrderElement orderElement) {
|
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
|
for (LocalDate day = start; day.compareTo(end) <= 0; day = day
|
||||||
.plusDays(1)) {
|
.plusDays(1)) {
|
||||||
final LocalDate textboxDate = day;
|
final LocalDate textboxDate = day;
|
||||||
|
|
||||||
final Textbox textbox = new Textbox();
|
final Textbox textbox = new Textbox();
|
||||||
textbox.setWidth("30px");
|
textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH);
|
||||||
|
|
||||||
Util.bind(textbox, new Util.Getter<String>() {
|
Util.bind(textbox, new Util.Getter<String>() {
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -108,7 +137,14 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
}
|
}
|
||||||
monthlyTimesheetModel.setEffortDuration(orderElement,
|
monthlyTimesheetModel.setEffortDuration(orderElement,
|
||||||
textboxDate, effortDuration);
|
textboxDate, effortDuration);
|
||||||
|
updateTotals(orderElement, textboxDate);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateTotals(OrderElement orderElement,
|
||||||
|
LocalDate date) {
|
||||||
updateTotalColumn(orderElement);
|
updateTotalColumn(orderElement);
|
||||||
|
updateTotalRow(date);
|
||||||
|
updateTotalColumn();
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
@ -120,6 +156,7 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
|
|
||||||
private void appendTotalColumn(Row row, final OrderElement orderElement) {
|
private void appendTotalColumn(Row row, final OrderElement orderElement) {
|
||||||
Textbox textbox = new Textbox();
|
Textbox textbox = new Textbox();
|
||||||
|
textbox.setWidth(EFFORT_DURATION_TEXTBOX_WIDTH);
|
||||||
textbox.setId(getTotalColumnTextboxId(orderElement));
|
textbox.setId(getTotalColumnTextboxId(orderElement));
|
||||||
textbox.setDisabled(true);
|
textbox.setDisabled(true);
|
||||||
row.appendChild(textbox);
|
row.appendChild(textbox);
|
||||||
|
|
@ -137,6 +174,65 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
orderElement).toFormattedString());
|
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
|
@Override
|
||||||
|
|
@ -210,12 +306,16 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
return monthlyTimesheetModel.getWorker().getShortDescription();
|
return monthlyTimesheetModel.getWorker().getShortDescription();
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<OrderElement> getOrderElements() {
|
public List<MonthlyTimesheetRow> getRows() {
|
||||||
return monthlyTimesheetModel.getOrderElements();
|
List<MonthlyTimesheetRow> result = MonthlyTimesheetRow
|
||||||
|
.wrap(monthlyTimesheetModel
|
||||||
|
.getOrderElements());
|
||||||
|
result.add(MonthlyTimesheetRow.createTotalRow());
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RowRenderer getOrderElementsRenderer() {
|
public RowRenderer getRowRenderer() {
|
||||||
return orderElementsRenderer;
|
return rowRenderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void save() {
|
public void save() {
|
||||||
|
|
@ -232,3 +332,56 @@ public class MonthlyTimesheetController extends GenericForwardComposer
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple class to represent the the rows in the monthly timesheet grid.<br />
|
||||||
|
*
|
||||||
|
* 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<MonthlyTimesheetRow> wrap(
|
||||||
|
List<OrderElement> orderElements) {
|
||||||
|
List<MonthlyTimesheetRow> result = new ArrayList<MonthlyTimesheetRow>();
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -244,4 +244,20 @@ public class MonthlyTimesheetModel implements IMonthlyTimesheetModel {
|
||||||
return result;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@
|
||||||
<groupbox style="margin-top: 5px" closable="false">
|
<groupbox style="margin-top: 5px" closable="false">
|
||||||
<caption label="${i18n:_('Time tracking')}" />
|
<caption label="${i18n:_('Time tracking')}" />
|
||||||
<grid id="timesheet"
|
<grid id="timesheet"
|
||||||
model="@{controller.orderElements}"
|
model="@{controller.rows}"
|
||||||
rowRenderer="@{controller.orderElementsRenderer}" />
|
rowRenderer="@{controller.rowRenderer}" />
|
||||||
</groupbox>
|
</groupbox>
|
||||||
|
|
||||||
<button onClick="controller.save();"
|
<button onClick="controller.save();"
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue