/* * This file is part of LibrePlan * * Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e * Desenvolvemento Tecnolóxico de Galicia * 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 * 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 <http://www.gnu.org/licenses/>. */ package org.libreplan.web.workreports; import static org.libreplan.web.I18nHelper._; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.lang3.Validate; import org.hibernate.Hibernate; import org.libreplan.business.common.IntegrationEntity; import org.libreplan.business.common.daos.IConfigurationDAO; import org.libreplan.business.common.entities.EntityNameEnum; import org.libreplan.business.common.exceptions.InstanceNotFoundException; import org.libreplan.business.common.exceptions.ValidationException; import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO; import org.libreplan.business.costcategories.entities.TypeOfWorkHours; import org.libreplan.business.labels.daos.ILabelDAO; import org.libreplan.business.labels.entities.Label; import org.libreplan.business.labels.entities.LabelType; import org.libreplan.business.orders.daos.IOrderElementDAO; import org.libreplan.business.orders.daos.ISumChargedEffortDAO; import org.libreplan.business.orders.entities.OrderElement; import org.libreplan.business.orders.entities.OrderLineGroup; import org.libreplan.business.resources.daos.IWorkerDAO; import org.libreplan.business.resources.entities.Resource; import org.libreplan.business.resources.entities.Worker; import org.libreplan.business.workreports.daos.IWorkReportDAO; import org.libreplan.business.workreports.daos.IWorkReportLineDAO; import org.libreplan.business.workreports.daos.IWorkReportTypeDAO; import org.libreplan.business.workreports.entities.WorkReport; import org.libreplan.business.workreports.entities.WorkReportLabelTypeAssignment; import org.libreplan.business.workreports.entities.WorkReportLine; import org.libreplan.business.workreports.entities.WorkReportType; import org.libreplan.business.workreports.valueobjects.DescriptionField; import org.libreplan.business.workreports.valueobjects.DescriptionValue; import org.libreplan.web.common.IntegrationEntityModel; import org.libreplan.web.common.concurrentdetection.OnConcurrentModification; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.zkoss.ganttz.IPredicate; /** * Model for UI operations related to {@link WorkReport}. * * @author Diego Pino García <dpino@igalia.com> * @author Susana Montes Pedreira <smontes@wirelessgalicia.com> * @author Manuel Rego Casasnovas <rego@igalia.com> */ @Service @Scope(BeanDefinition.SCOPE_PROTOTYPE) @OnConcurrentModification(goToPage = "/workreports/workReport.zul") public class WorkReportModel extends IntegrationEntityModel implements IWorkReportModel { @Autowired private IWorkReportTypeDAO workReportTypeDAO; @Autowired private IWorkReportDAO workReportDAO; @Autowired private IWorkReportLineDAO workReportLineDAO; @Autowired private IOrderElementDAO orderElementDAO; @Autowired private IWorkerDAO workerDAO; @Autowired private ILabelDAO labelDAO; @Autowired private IConfigurationDAO configurationDAO; @Autowired private ITypeOfWorkHoursDAO typeOfWorkHoursDAO; @Autowired private ISumChargedEffortDAO sumChargedEffortDAO; private WorkReportType workReportType; private WorkReport workReport; private boolean editing = false; private static final Map<LabelType, List<Label>> mapLabelTypes = new HashMap<>(); private List<WorkReportDTO> listWorkReportDTOs = new ArrayList<>(); private List<WorkReportLine> listWorkReportLine = new ArrayList<>(); private Set<WorkReportLine> deletedWorkReportLinesSet = new HashSet<>(); @Override public WorkReport getWorkReport() { return workReport; } @Override public WorkReportType getWorkReportType() { return this.workReportType; } @Override @Transactional(readOnly = true) public void initCreate(WorkReportType workReportType) { editing = false; forceLoadWorkReportTypeFromDB(workReportType); workReport = WorkReport.create(this.workReportType); workReport.setCodeAutogenerated(configurationDAO.getConfiguration().getGenerateCodeForWorkReport()); if (!workReport.isCodeAutogenerated()) { workReport.setCode(""); }else{ setDefaultCode(); } loadMaps(); deletedWorkReportLinesSet = new HashSet<>(); } @Override @Transactional(readOnly = true) public void initEdit(WorkReport workReport) { editing = true; Validate.notNull(workReport); this.workReport = getFromDB(workReport); forceLoadWorkReportTypeFromDB(workReport.getWorkReportType()); loadMaps(); initOldCodes(); deletedWorkReportLinesSet = new HashSet<>(); } @Transactional(readOnly = true) private WorkReport getFromDB(WorkReport workReport) { return getFromDB(workReport.getId()); } @Transactional(readOnly = true) private WorkReport getFromDB(Long id) { try { WorkReport result = workReportDAO.find(id); forceLoadEntities(result); return result; } catch (InstanceNotFoundException e) { throw new RuntimeException(e); } } /** * Load entities that will be needed in the conversation. * * @param workReport */ private void forceLoadEntities(WorkReport workReport) { // Load WorkReportType workReport.getWorkReportType().getName(); if (workReport.getResource() != null) { workReport.getResource().getShortDescription(); } if (workReport.getOrderElement() != null) { workReport.getOrderElement().getCode(); } // Load Labels for (Label label : workReport.getLabels()) { label.getName(); label.getType().getName(); } // Load DescriptionValues for (DescriptionValue descriptionValue : workReport.getDescriptionValues()) { descriptionValue.getFieldName(); } // Load WorkReportLines for (WorkReportLine workReportLine : workReport.getWorkReportLines()) { //Load pricipal data forceLoadPrincipalDataWorkReportLines(workReportLine); // Load Labels for (Label label : workReportLine.getLabels()) { label.getName(); label.getType().getName(); } // Load DescriptionValues for (DescriptionValue descriptionValue : workReportLine.getDescriptionValues()) { descriptionValue.getFieldName(); } } } private void forceLoadPrincipalDataWorkReportLines(WorkReportLine line) { line.getEffort().getHours(); line.getResource().getShortDescription(); line.getTypeOfWorkHours().getName(); initializeOrderElement(line.getOrderElement()); } private void initializeOrderElement(OrderElement orderElement) { Hibernate.initialize(orderElement); Hibernate.initialize(orderElement.getChildren()); initializeOrder(orderElement); } private void initializeOrder(OrderElement orderElement) { OrderLineGroup parent = orderElement.getParent(); while (parent != null) { Hibernate.initialize(parent); parent = parent.getParent(); } } private void forceLoadWorkReportTypeFromDB(WorkReportType workReportType) { this.workReportType = getWorkReportTypeFromDB(workReportType.getId()); forceLoadCollections(this.workReportType); } @Transactional(readOnly = true) private WorkReportType getWorkReportTypeFromDB(Long id) { try { return workReportTypeDAO.find(id); } catch (InstanceNotFoundException e) { throw new RuntimeException(e); } } private void forceLoadCollections(WorkReportType workReportType) { for (DescriptionField line : workReportType.getLineFields()) { line.getFieldName(); } for (DescriptionField head : workReportType.getHeadingFields()) { head.getFieldName(); } for (WorkReportLabelTypeAssignment assignedLabel : workReportType.getWorkReportLabelTypeAssignments()) { assignedLabel.getDefaultLabel().getName(); assignedLabel.getLabelType().getName(); } } @Override @Transactional public void confirmSave() throws ValidationException { Set<OrderElement> orderElements = sumChargedEffortDAO.getOrderElementsToRecalculateTimsheetDates( workReport.getWorkReportLines(), deletedWorkReportLinesSet); sumChargedEffortDAO.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(deletedWorkReportLinesSet); sumChargedEffortDAO.updateRelatedSumChargedEffortWithWorkReportLineSet(workReport.getWorkReportLines()); workReportDAO.save(workReport); sumChargedEffortDAO.recalculateTimesheetData(orderElements); } @Override @Transactional public void generateWorkReportLinesIfIsNecessary() { if (workReport.isCodeAutogenerated()) { generateWorkReportLineCodes(); } } private void generateWorkReportLineCodes() { workReport.generateWorkReportLineCodes(getNumberOfDigitsCode()); } @Override @Transactional public OrderElement findOrderElement(String orderCode) throws InstanceNotFoundException { OrderElement result = orderElementDAO.findUniqueByCode(orderCode); initializeChildren(result); return result; } private void initializeChildren(OrderElement order) { for (OrderElement each: order.getAllChildren()) { Hibernate.initialize(each); } } @Override @Transactional public Worker findWorker(String nif) throws InstanceNotFoundException { return workerDAO.findUniqueByNif(nif); } @Override @Transactional public Worker asWorker(Resource resource) throws InstanceNotFoundException { return workerDAO.find(resource.getId()); } @Override @Transactional(readOnly = true) public List<WorkReportDTO> getWorkReportDTOs() { // Load the work reports DTOs listWorkReportDTOs.clear(); for (WorkReport workReport : getAllWorkReports()) { WorkReportDTO workReportDTO = new WorkReportDTO(workReport); listWorkReportDTOs.add(workReportDTO); } return listWorkReportDTOs; } @Override @Transactional(readOnly = true) public List<WorkReportDTO> getFilterWorkReportDTOs(IPredicate predicate) { List<WorkReportDTO> resultDTOs = new ArrayList<>(); for (WorkReportDTO workReportDTO : listWorkReportDTOs) { if (predicate.accepts(workReportDTO)) { resultDTOs.add(workReportDTO); } } return resultDTOs; } private List<WorkReport> getAllWorkReports() { List<WorkReport> result = new ArrayList<>(); for (WorkReport each : workReportDAO.allWorkReportsWithAssociatedOrdersUnproxied()) { each.getWorkReportType().getName(); if (each.getResource() != null) { each.getResource().getShortDescription(); } if (each.getOrderElement() != null) { each.getOrderElement().getName(); each.getOrderElement().getOrder(); } result.add(each); } return result; } @Override @Transactional(readOnly = true) public List<WorkReportLine> getAllWorkReportLines() { listWorkReportLine.clear(); for (WorkReport workReport : getAllWorkReports()) { for (WorkReportLine workReportLine : workReport.getWorkReportLines()) { forceLoadPrincipalDataWorkReportLines(workReportLine); listWorkReportLine.add(workReportLine); } } return listWorkReportLine; } @Override public List<WorkReportLine> getFilterWorkReportLines(IPredicate predicate) { List<WorkReportLine> result = new ArrayList<>(); for (WorkReportLine workReportLine : listWorkReportLine) { if (predicate.accepts(workReportLine)) { result.add(workReportLine); } } return result; } @Override public boolean isEditing() { return editing; } @Override public WorkReportLine addWorkReportLine() { if (workReport != null) { WorkReportLine workReportLine = WorkReportLine.create(workReport); workReportLine.setCode(""); // Adding default date workReportLine.setDate(new Date()); workReport.addWorkReportLine(workReportLine); return workReportLine; } return null; } @Override @Transactional public void remove(WorkReport workReport) { // Before deleting the report, update OrderElement.SumChargedHours() try { workReportDAO.reattach(workReport); Set<OrderElement> orderElements = sumChargedEffortDAO.getOrderElementsToRecalculateTimsheetDates(null, workReport.getWorkReportLines()); sumChargedEffortDAO.updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(workReport.getWorkReportLines()); workReportDAO.remove(workReport.getId()); sumChargedEffortDAO.recalculateTimesheetData(orderElements); } catch (InstanceNotFoundException e) { throw new RuntimeException(e); } } @Override public void removeWorkReportLine(WorkReportLine workReportLine) { deletedWorkReportLinesSet.add(workReportLine); workReport.removeWorkReportLine(workReportLine); } @Override public List<WorkReportLine> getWorkReportLines() { List<WorkReportLine> result = new ArrayList<>(); if (getWorkReport() != null) { result.addAll(workReport.getWorkReportLines()); } return result; } /** * Operations to manage the Description Fields and the assigned labels. */ @Override public List<Object> getFieldsAndLabelsLineByDefault() { if ((getWorkReport() != null)) { return sort(getWorkReportType().getLineFieldsAndLabels()); } return new ArrayList<>(); } @Override public List<Object> getFieldsAndLabelsHeading() { List<Object> result = new ArrayList<>(); if (getWorkReport() != null) { result.addAll(getWorkReport().getDescriptionValues()); result.addAll(getWorkReport().getLabels()); return sort(result); } return result; } @Override public List<Object> getFieldsAndLabelsLine(WorkReportLine workReportLine) { List<Object> result = new ArrayList<>(); if ((getWorkReport() != null) && (workReportLine != null)) { result.addAll(workReportLine.getDescriptionValues()); result.addAll(workReportLine.getLabels()); return sort(result); } return result; } @Override public Map<LabelType, List<Label>> getMapAssignedLabelTypes() { return this.mapLabelTypes; } @Override public void changeLabelInWorkReportLine(Label oldLabel, Label newLabel, WorkReportLine line) { if (line != null) { line.getLabels().remove(oldLabel); line.getLabels().add(newLabel); } } @Override @Transactional(readOnly = true) public void changeLabelInWorkReport(Label oldLabel, Label newLabel) { if (getWorkReport() != null) { getWorkReport().getLabels().remove(oldLabel); getWorkReport().getLabels().add(newLabel); } } private void loadMaps() { loadLabelsByAssignedType(); } private void loadLabelsByAssignedType() { mapLabelTypes.clear(); // Get the all assigned label types for (LabelType labelType : getAssignedLabelTypes()) { List<Label> labels = new ArrayList<>(labelDAO.findByType(labelType)); mapLabelTypes.put(labelType, labels); } } private DescriptionField getDescriptionFieldByName(String name){ for (DescriptionField descriptionField : getWorkReportType().getDescriptionFields()) { if(descriptionField.getFieldName().equals(name)){ return descriptionField; } } return null; } private Integer getAssignedLabelIndex(Label label){ for (WorkReportLabelTypeAssignment labelTypeAssignment : getWorkReportType().getWorkReportLabelTypeAssignments()) { if (labelTypeAssignment.getLabelType().equals(label.getType())) { return labelTypeAssignment.getPositionNumber(); } } return null; } private List<Object> sort(List<Object> list) { List<Object> result = new ArrayList<>(list); if (list != null) { for (Object object : list) { Integer index = getIndex(object); if ((index != null) && ((index >= 0) && (index < list.size()))) { result.set(getIndex(object), object); } } } return result; } private List<LabelType> getAssignedLabelTypes() { List<LabelType> result = new ArrayList<>(); for (WorkReportLabelTypeAssignment labelTypeAssignment : getWorkReportType().getWorkReportLabelTypeAssignments()) { result.add(labelTypeAssignment.getLabelType()); } return result; } private Integer getIndex(Object object) { if (object instanceof DescriptionValue) { DescriptionField descriptionField = getDescriptionFieldByName(((DescriptionValue) object).getFieldName()); return descriptionField.getPositionNumber(); } if (object instanceof Label) { return getAssignedLabelIndex((Label) object); } if (object instanceof DescriptionField) { return ((DescriptionField) object).getPositionNumber(); } if (object instanceof WorkReportLabelTypeAssignment) { return ((WorkReportLabelTypeAssignment) object).getPositionNumber(); } return null; } @Override public Integer getLength(DescriptionValue descriptionValue) { DescriptionField descriptionField = getDescriptionFieldByName(descriptionValue.getFieldName()); return descriptionField.getLength(); } /** * Set the selected default work report type to filter the work reports. */ public final String SHOW_ALL_TYPES = _("Show all"); private final WorkReportType defaultType = WorkReportType.create(SHOW_ALL_TYPES, ""); @Override public WorkReportType getDefaultType() { return defaultType; } @Override @Transactional(readOnly = true) public List<WorkReportType> getWorkReportTypes() { return workReportTypeDAO.list(WorkReportType.class); } @Override @Transactional(readOnly = true) public List<OrderElement> getOrderElements() { return orderElementDAO.getAll(); } @Override public EntityNameEnum getEntityName() { return EntityNameEnum.WORK_REPORT; } @Override public Set<IntegrationEntity> getChildren() { return (Set<IntegrationEntity>) (workReport != null ? workReport.getWorkReportLines() : new HashSet<IntegrationEntity>()); } @Override public IntegrationEntity getCurrentEntity() { return this.workReport; } @Override @Transactional(readOnly = true) public List<TypeOfWorkHours> getAllHoursType() { return typeOfWorkHoursDAO.hoursTypeByNameAsc(); } @Override @Transactional(readOnly = true) public List<Worker> getBoundWorkers() { return workerDAO.getBound(); } @Override @Transactional(readOnly = true) public boolean isPersonalTimesheet(WorkReport workReport) { try { return workReportTypeDAO.find(workReport.getWorkReportType().getId()).isPersonalTimesheetsType(); } catch (InstanceNotFoundException e) { throw new RuntimeException(e); } } @Override public WorkReportLine getFirstWorkReportLine() { return workReport.getWorkReportLines().iterator().next(); } @Override @Transactional(readOnly = true) public boolean isFinished(OrderElement orderElement) { if (workReport.isFinished(orderElement)) { return true; } List<WorkReportLine> lines = workReportLineDAO.findFinishedByOrderElementNotInWorkReportAnotherTransaction(orderElement, workReport); return !lines.isEmpty(); } }