diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java index 69741694e..c2ac2169c 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/CustomMenuController.java @@ -206,8 +206,13 @@ public class CustomMenuController extends Div implements IMenuItemsRegister { subItem(_("Virtual worker groups"),"/resources/worker/virtualWorkers.zul","05-recursos.html#xesti-n-de-traballadores")); topItem(_("Work reports"), "/workreports/workReportTypes.zul", "", - subItem(_("Work report types"),"/workreports/workReportTypes.zul","09-partes.html#id2"), - subItem(_("Work report list"), "/workreports/workReport.zul", "09-partes.html#id3")); + subItem(_("Work report types"), + "/workreports/workReportTypes.zul", + "09-partes.html#id2"), subItem(_("Work report list"), + "/workreports/workReport.zul", "09-partes.html#id3"), + subItem(_("Work report query"), + "/workreports/workReportQuery.zul", + "09-partes.html#id4")); if (SecurityUtils.isUserInRole(UserRole.ROLE_ADMINISTRATION)) { topItem(_("Administration"), "/advance/advanceTypes.zul", "", @@ -222,8 +227,8 @@ public class CustomMenuController extends Div implements IMenuItemsRegister { subItem(_("Quality forms"),"/qualityforms/qualityForms.zul",""), subItem(_("Manage user profiles"), "/users/profiles.zul",""), subItem(_("Manage user accounts"), "/users/users.zul","")); - } - topItem(_("Reports"), "", "", + } + topItem(_("Reports"), "", "", subItem(_("Hours worked per worker"), "/reports/hoursWorkedPerWorkerReport.zul", ""), subItem(_("Completed estimated hours per task"), diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFinder.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFinder.java index 57e44b3ba..ee6d4b758 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFinder.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/components/finders/ResourceFinder.java @@ -24,14 +24,13 @@ import java.util.List; import org.navalplanner.business.resources.daos.IResourceDAO; import org.navalplanner.business.resources.entities.Resource; -import org.navalplanner.business.resources.entities.Worker; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; import org.springframework.transaction.annotation.Transactional; /** * @author Susana Montes Pedreira Implements a - * {@link IFinder} class for providing {@link Worker} elements + * {@link IFinder} class for providing {@link Resource} elements */ @Repository public class ResourceFinder extends Finder implements IFinder { diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/common/typeconverters/TimeConverter.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/typeconverters/TimeConverter.java new file mode 100644 index 000000000..ac4f140e1 --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/common/typeconverters/TimeConverter.java @@ -0,0 +1,48 @@ +/* + * 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.common.typeconverters; + +import java.text.SimpleDateFormat; +import java.util.Date; + +import org.zkoss.zk.ui.Component; +import org.zkoss.zkplus.databind.TypeConverter; + +/** + * Converter for the type java.util.Date + * + * @author Susana Montes Pedreira + * + */ +public class TimeConverter implements TypeConverter { + + @Override + public Object coerceToBean(Object arg0, Component arg1) { + return null; + } + + @Override + public Object coerceToUi(Object object, Component component) { + Date date = ((Date)object); + return object != null ? (new SimpleDateFormat("h:mm a")) + .format((Date) object) : new String(""); + } +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/IWorkReportModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/IWorkReportModel.java index 7bf365f2d..ec1906faf 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/IWorkReportModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/IWorkReportModel.java @@ -39,8 +39,8 @@ import org.navalplanner.web.orders.IPredicate; /** * Contract for {@link WorkRerportType} - * * @author Diego Pino García + * @author Susana Montes Pedreira */ public interface IWorkReportModel { @@ -53,7 +53,6 @@ public interface IWorkReportModel { /** * Converts @{link Resource} to @{link Worker} - * * @param resource * @return * @throws InstanceNotFoundException @@ -105,14 +104,39 @@ public interface IWorkReportModel { List getWorkReportTypes(); /** - * Returns true if WorkReport is being edited + * Return all the {@link WorkReportLine} + * @return + */ + List getAllWorkReportLines(); + + /** + * Return all the {@link WorkReportLine} are filtered by a predicate + * @return + */ + List getFilterWorkReportLines(IPredicate predicate); + + /** + * Returns true if {@link WorkReport} is being edited * @return */ boolean isEditing(); + /** + * Returns true if {@link WorkReport} is being edited from the query of the + * {@link WorkReportLine} list + * @return + */ + boolean isListingQuery(); + + /** + * Set if the {@link WorkReport} is being edited from the query of the + * {@link WorkReportLine} list + * @return + */ + void setListingQuery(boolean listingQuery); + /** * Makes some operations needed before edit a {@link WorkReport}. - * * @param workReport * The object to be edited */ diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportCRUDController.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportCRUDController.java index 45f58b09d..262ee2abb 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportCRUDController.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportCRUDController.java @@ -85,8 +85,8 @@ import org.zkoss.zul.api.Window; /** * Controller for CRUD actions over a {@link WorkReport} - * * @author Diego Pino García + * @author Susana Montes Pedreira */ public class WorkReportCRUDController extends GenericForwardComposer implements IWorkReportCRUDControllerEntryPoints { @@ -97,6 +97,8 @@ public class WorkReportCRUDController extends GenericForwardComposer implements private Window listWindow; + private Window listQueryWindow; + private IWorkReportModel workReportModel; private IURLHandlerRegistry URLHandlerRegistry; @@ -137,6 +139,20 @@ public class WorkReportCRUDController extends GenericForwardComposer implements private Datebox filterFinishDate; + private IPredicate predicateFilterLines; + + private Grid gridListQuery; + + private Autocomplete filterResource; + + private Datebox filterStartDateLine; + + private Datebox filterFinishDateLine; + + private Textbox filterOrderElement; + + private Autocomplete filterHoursType; + @Override public void doAfterCompose(Component comp) throws Exception { super.doAfterCompose(comp); @@ -147,7 +163,16 @@ public class WorkReportCRUDController extends GenericForwardComposer implements final URLHandler handler = URLHandlerRegistry .getRedirectorFor(IWorkReportCRUDControllerEntryPoints.class); handler.registerListener(this, page); - goToList(); + initCurrentList(); + } + + private void initCurrentList() { + if (listWindow != null) { + workReportModel.setListingQuery(false); + } else if (listQueryWindow != null) { + workReportModel.setListingQuery(true); + } + this.goToList(); } /** @@ -184,7 +209,7 @@ public class WorkReportCRUDController extends GenericForwardComposer implements private OnlyOneVisible getVisibility() { return (visibility == null) ? new OnlyOneVisible(createWindow, - listWindow) + listWindow, listQueryWindow) : visibility; } @@ -470,11 +495,25 @@ public class WorkReportCRUDController extends GenericForwardComposer implements @Override public void goToList() { + if (workReportModel.isListingQuery()) { + goToListQueryWorkReportLines(); + } else { + goToListWorkReports(); + } + } + + public void goToListWorkReports() { getVisibility().showOnly(listWindow); loadComponentslist(listWindow); Util.reloadBindings(listWindow); } + public void goToListQueryWorkReportLines() { + getVisibility().showOnly(listQueryWindow); + loadComponentslistLines(listQueryWindow); + Util.reloadBindings(listQueryWindow); + } + public void cancel() { if (workReportModel.isEditing()) { goToList(); @@ -492,8 +531,8 @@ public class WorkReportCRUDController extends GenericForwardComposer implements } public void goToEditForm(WorkReportDTO workReportDTO) { - WorkReport workReport = workReportDTO.getWorkReport(); - goToEditForm(workReport); + workReportModel.setListingQuery(false); + goToEditForm(workReportDTO.getWorkReport()); } public void goToEditForm(WorkReport workReport) { @@ -523,6 +562,16 @@ public class WorkReportCRUDController extends GenericForwardComposer implements clearFilterDates(); } + private void loadComponentslistLines(Component window) { + gridListQuery = (Grid) window.getFellow("gridListQuery"); + filterResource = (Autocomplete) window.getFellow("filterResource"); + filterStartDateLine = (Datebox) window.getFellow("filterStartDateLine"); + filterFinishDateLine = (Datebox) window + .getFellow("filterFinishDateLine"); + filterOrderElement = (Textbox) window.getFellow("filterOrderElement"); + filterHoursType = (Autocomplete) window.getFellow("filterHoursType"); + clearFilterDatesLines(); + } /** * {@link WorkReportLine} list is finally constructed dynamically * @@ -1405,4 +1454,132 @@ public class WorkReportCRUDController extends GenericForwardComposer implements return workReportModel.getOrderElements(); } + /** + * Method to manage the query work report lines + */ + + public List getQueryWorkReportLines() { + return workReportModel.getAllWorkReportLines(); + } + + public void sortQueryWorkReportLines() { + Column columnDateLine = (Column) listQueryWindow.getFellow("date"); + if (columnDateLine != null) { + if (columnDateLine.getSortDirection().equals("ascending")) { + columnDateLine.sort(false, false); + columnDateLine.setSortDirection("ascending"); + } else if (columnDateLine.getSortDirection().equals("descending")) { + columnDateLine.sort(true, false); + columnDateLine.setSortDirection("descending"); + } + } + } + + public void goToEditFormQuery(WorkReportLine line) { + workReportModel.setListingQuery(true); + goToEditForm(line.getWorkReport()); + } + + /** + * Apply filter to work report lines + * @param event + */ + public void onApplyFilterWorkReportLines(Event event) { + createPredicateLines(); + filterByPredicateLines(); + } + + private void createPredicateLines() { + Resource resource = getSelectedResource(); + Date startDate = filterStartDateLine.getValue(); + Date finishDate = filterFinishDateLine.getValue(); + OrderElement orderElement = getSelectedOrderElement(); + TypeOfWorkHours hoursType = getSelectedHoursType(); + predicateFilterLines = new WorkReportLinePredicate(resource, startDate, + finishDate, orderElement, hoursType); + } + + private Resource getSelectedResource() { + Comboitem itemSelected = filterResource.getSelectedItem(); + if ((itemSelected != null) + && (((Resource) itemSelected.getValue()) != null)) { + return (Resource) itemSelected.getValue(); + } + return null; + } + + public OrderElement getSelectedOrderElement() { + String code = filterOrderElement.getValue(); + if ((code != null) && (!code.isEmpty())) { + try { + return workReportModel.findOrderElement(code); + } catch (InstanceNotFoundException e) { + throw new WrongValueException(filterOrderElement, + _("OrderElement not found")); + } + } + return null; + } + + private TypeOfWorkHours getSelectedHoursType() { + Comboitem itemSelected = filterHoursType.getSelectedItem(); + if ((itemSelected != null) + && (((TypeOfWorkHours) itemSelected.getValue()) != null)) { + return (TypeOfWorkHours) itemSelected.getValue(); + } + return null; + } + + private void filterByPredicateLines() { + List filterWorkReportLines = workReportModel + .getFilterWorkReportLines(predicateFilterLines); + gridListQuery.setModel(new SimpleListModel(filterWorkReportLines + .toArray())); + gridListQuery.invalidate(); + } + + private void clearFilterDatesLines() { + filterResource.setValue(null); + filterOrderElement.setValue(""); + filterStartDateLine.setValue(null); + filterFinishDateLine.setValue(null); + filterHoursType.setValue(null); + } + + public Constraint checkConstraintFinishDateLine() { + return new Constraint() { + @Override + public void validate(Component comp, Object value) + throws WrongValueException { + Date finishDateLine = (Date) value; + if ((finishDateLine != null) + && (filterStartDateLine.getValue() != null) + && (finishDateLine.compareTo(filterStartDateLine + .getValue()) < 0)) { + filterFinishDateLine.setValue(null); + throw new WrongValueException(comp, + _("must be greater than start date")); + } + } + }; + } + + public Constraint checkConstraintStartDateLine() { + return new Constraint() { + @Override + public void validate(Component comp, Object value) + throws WrongValueException { + Date startDateLine = (Date) value; + if ((startDateLine != null) + && (filterFinishDateLine.getValue() != null) + && (startDateLine.compareTo(filterFinishDateLine + .getValue()) > 0)) { + filterStartDateLine.setValue(null); + throw new WrongValueException(comp, + _("must be lower than finish date")); + } + } + }; + } + } diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportLinePredicate.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportLinePredicate.java new file mode 100644 index 000000000..bfee061bc --- /dev/null +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportLinePredicate.java @@ -0,0 +1,111 @@ +/* + * 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.workreports; + +import java.util.Date; + +import org.navalplanner.business.common.BaseEntity; +import org.navalplanner.business.costcategories.entities.TypeOfWorkHours; +import org.navalplanner.business.orders.entities.OrderElement; +import org.navalplanner.business.resources.entities.Resource; +import org.navalplanner.business.workreports.entities.WorkReportLine; +import org.navalplanner.web.orders.IPredicate; + +/** + * Checks if {@link WorkReportLine} matches the constraints + * @author Susana Montes Pedreira + */ +public class WorkReportLinePredicate implements IPredicate { + + private Resource resource; + private Date startDate; + private Date finishDate; + private OrderElement orderElement; + private TypeOfWorkHours hourType; + + public WorkReportLinePredicate(Resource resource, Date startDate, + Date finishDate, OrderElement orderElement, TypeOfWorkHours hourType) { + this.resource = resource; + this.startDate = startDate; + this.finishDate = finishDate; + this.orderElement = orderElement; + this.hourType = hourType; + } + + @Override + public boolean accepts(Object object) { + WorkReportLine line = (WorkReportLine) object; + return (isEqual(resource, line.getResource()) + && isEqual(orderElement, line.getOrderElement()) + && isEqual(hourType, line.getTypeOfWorkHours()) && acceptFiltersDates(line)); + } + + private boolean isEqual(BaseEntity entityPredicate, BaseEntity entityLine) { + if ((entityLine == null) || (entityPredicate == null)) { + return true; + } + return entityPredicate.getId().equals(entityLine.getId()); + } + + private boolean acceptFiltersDates(WorkReportLine workReportLine) { + // Check if exist work report items into interval between the start date + // and finish date. + if (isInTheRangeFilterDates(workReportLine.getDate())) { + return true; + } + return false; + } + + private boolean isInTheRangeFilterDates(Date date) { + // Check if date is into interval between the startdate and finish date + return (isGreaterToStartDate(date, startDate) && isLowerToFinishDate( + date, finishDate)); + } + + private boolean isInTheRangeWorkReportDates(Date date, + WorkReportDTO workReportDTO) { + // Check if date is into interval between the startdate and finish date + return (isGreaterToStartDate(date, workReportDTO.getDateStart()) && isLowerToFinishDate( + date, workReportDTO.getDateFinish())); + } + + private boolean isGreaterToStartDate(Date date, Date startDate) { + if (startDate == null) { + return true; + } + + if (date != null && (date.compareTo(startDate) >= 0)) { + return true; + } + return false; + } + + private boolean isLowerToFinishDate(Date date, Date finishDate) { + if (finishDate == null) { + return true; + } + if (date != null && (date.compareTo(finishDate) <= 0)) { + return true; + } + return false; + } + +} diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportModel.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportModel.java index 98c91e2ab..bcf9a34c4 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportModel.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/workreports/WorkReportModel.java @@ -55,8 +55,8 @@ import org.springframework.transaction.annotation.Transactional; /** * Model for UI operations related to {@link WorkReport}. - * * @author Diego Pino García + * @author Susana Montes Pedreira */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) @@ -83,6 +83,8 @@ public class WorkReportModel implements IWorkReportModel { private boolean editing = false; + private boolean listingQuery = false; + private Map mapDescriptonValues = new HashMap(); private Map mapLabels = new HashMap(); @@ -91,6 +93,8 @@ public class WorkReportModel implements IWorkReportModel { private List listWorkReportDTOs = new ArrayList(); + private List listWorkReportLine = new ArrayList(); + @Override public WorkReport getWorkReport() { return workReport; @@ -164,10 +168,8 @@ public class WorkReportModel implements IWorkReportModel { // Load WorkReportLines for (WorkReportLine workReportLine : workReport.getWorkReportLines()) { - workReportLine.getNumHours(); - workReportLine.getResource().getShortDescription(); - workReportLine.getOrderElement().getName(); - workReportLine.getTypeOfWorkHours().getName(); + //Load pricipal data + forceLoadPrincipalDataWorkReportLines(workReportLine); // Load Labels for (Label label : workReportLine.getLabels()) { @@ -180,10 +182,16 @@ public class WorkReportModel implements IWorkReportModel { .getDescriptionValues()) { descriptionValue.getFieldName(); } - } } + private void forceLoadPrincipalDataWorkReportLines(WorkReportLine line) { + line.getNumHours(); + line.getResource().getShortDescription(); + line.getOrderElement().getName(); + line.getTypeOfWorkHours().getName(); + } + private void forceLoadWorkReportTypeFromDB(WorkReportType workReportType) { this.workReportType = getWorkReportTypeFromDB(workReportType.getId()); forceLoadCollections(this.workReportType); @@ -279,11 +287,46 @@ public class WorkReportModel implements IWorkReportModel { return result; } + @Override + @Transactional(readOnly = true) + public List getAllWorkReportLines() { + listWorkReportLine.clear(); + for (WorkReport workReport : getAllWorkReports()) { + for (WorkReportLine workReportLine : workReport + .getWorkReportLines()) { + forceLoadPrincipalDataWorkReportLines(workReportLine); + listWorkReportLine.add(workReportLine); + } + } + return listWorkReportLine; + } + + @Override + public List getFilterWorkReportLines(IPredicate predicate) { + List result = new ArrayList(); + for (WorkReportLine workReportLine : listWorkReportLine) { + if (predicate.accepts(workReportLine)) { + result.add(workReportLine); + } + } + return result; + } + @Override public boolean isEditing() { return editing; } + @Override + public boolean isListingQuery() { + return this.listingQuery; + } + + @Override + public void setListingQuery(boolean listingQuery) { + this.listingQuery = listingQuery; + } + @Override public WorkReportLine addWorkReportLine() { WorkReportLine workReportLine = WorkReportLine.create(); diff --git a/navalplanner-webapp/src/main/webapp/workreports/_listWorkReportQuery.zul b/navalplanner-webapp/src/main/webapp/workreports/_listWorkReportQuery.zul new file mode 100644 index 000000000..e6841ab7e --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/workreports/_listWorkReportQuery.zul @@ -0,0 +1,80 @@ + + + + + + +
+ + +
+ +
+
+ + + + + + + + + + + + + + + + + +
diff --git a/navalplanner-webapp/src/main/webapp/workreports/workReportQuery.zul b/navalplanner-webapp/src/main/webapp/workreports/workReportQuery.zul new file mode 100644 index 000000000..bdb3c079e --- /dev/null +++ b/navalplanner-webapp/src/main/webapp/workreports/workReportQuery.zul @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + +