Package org.libreplan.business.workreports.entities

Source Code of org.libreplan.business.workreports.entities.WorkReport

/*
* 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.business.workreports.entities;

import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import javax.validation.constraints.AssertTrue;
import javax.validation.constraints.NotNull;
import javax.validation.Valid;
import org.joda.time.LocalDate;
import org.libreplan.business.common.IntegrationEntity;
import org.libreplan.business.common.Registry;
import org.libreplan.business.common.Util;
import org.libreplan.business.common.entities.EntitySequence;
import org.libreplan.business.common.entities.PersonalTimesheetsPeriodicityEnum;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
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.resources.entities.Worker;
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;

/**
* @author Diego Pino García <dpino@igalia.com>
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
* @author Manuel Rego Casasnovas <mrego@igalia.com>
*/
public class WorkReport extends IntegrationEntity implements
        IWorkReportsElements {

    public static final String DATE = "date";
    public static final String RESOURCE = "resource";
    public static final String ORDERELEMENT = "orderElement";

    public static WorkReport create() {
        return create(new WorkReport());
    }

    public static WorkReport create(WorkReportType workReportType) {
        return create(new WorkReport(workReportType));
    }

    public static WorkReport create(Date date,
            WorkReportType workReportType, Set<WorkReportLine> workReportLines,
            Resource resource, OrderElement orderElement) {
        WorkReport workReport = new WorkReport(date, workReportType,
                workReportLines, resource, orderElement);
        return create(workReport);
    }

    private Date date;

    private WorkReportType workReportType;

    private Resource resource;

    private OrderElement orderElement;

    private Set<Label> labels = new HashSet<Label>();

    private Set<WorkReportLine> workReportLines = new HashSet<WorkReportLine>();

    private Set<DescriptionValue> descriptionValues = new HashSet<DescriptionValue>();

    private Integer lastWorkReportLineSequenceCode = 0;
    /**
     * Constructor for hibernate. Do not use!
     */
    public WorkReport() {

    }

    private WorkReport(WorkReportType workReportType) {
        this.setWorkReportType(workReportType);
    }

    private WorkReport(Date date, WorkReportType workReportType,
            Set<WorkReportLine> workReportLines, Resource resource,
            OrderElement orderElement) {
        this.date = date;
        this.setWorkReportType(workReportType);
        this.workReportLines = workReportLines;
        this.resource = resource;
        this.orderElement = orderElement;
    }

    @Override
    public Date getDate() {
        return date != null ? new Date(date.getTime()) : null;
    }

    @Override
    public void setDate(Date date) {
        this.date = date != null ? new Date(date.getTime()) : null;
        if (workReportType != null) {
            if (workReportType.getDateIsSharedByLines()) {
                updateSharedDateByLines(date);
            } else {
                this.date = null;
            }
        }
    }

    @NotNull(message = "timesheet template not specified")
    public WorkReportType getWorkReportType() {
        return workReportType;
    }

    /**
     * Set the new {@link WorkReportType} and validate if the new
     * {@link WorkReportType} is different to the old {@link WorkReportType}.If
     * the new {@link WorkReportType} is different it updates the assigned
     * fields and labels of the new {@link WorkReportType}.
     * @param {@link WorkReportType}
     */
    public void setWorkReportType(WorkReportType workReportType) {
        this.workReportType = workReportType;

        updateSharedDateByLines(date);
        updateSharedResourceByLines(resource);
        updateSharedOrderElementByLines(orderElement);
        updateItsFieldsAndLabels(workReportType);
    }

    @Valid
    public Set<WorkReportLine> getWorkReportLines() {
        return Collections.unmodifiableSet(workReportLines);
    }

    public void addWorkReportLine(WorkReportLine workReportLine) {
        workReportLines.add(workReportLine);
    }

    public void removeWorkReportLine(WorkReportLine workReportLine) {
        workReportLines.remove(workReportLine);
    }

    @Override
    @Valid
    public Set<DescriptionValue> getDescriptionValues() {
        return Collections.unmodifiableSet(descriptionValues);
    }

    @Override
    public void setDescriptionValues(Set<DescriptionValue> descriptionValues) {
        this.descriptionValues = descriptionValues;
    }

    @Override
    public Set<Label> getLabels() {
        return labels;
    }

    @Override
    public void setLabels(Set<Label> labels) {
        this.labels = labels;
    }

    @Override
    public Resource getResource() {
        return resource;
    }

    @Override
    public void setResource(Resource resource) {
        this.resource = resource;
        if (workReportType != null) {
            if (workReportType.getResourceIsSharedInLines()) {
                updateSharedResourceByLines(resource);
            } else {
                this.resource = null;
            }
        }
    }

    @Override
    public OrderElement getOrderElement() {
        return orderElement;
    }

    @Override
    public void setOrderElement(OrderElement orderElement) {
        this.orderElement = orderElement;
        if (workReportType != null) {
            if (workReportType.getOrderElementIsSharedInLines()) {
                this.updateSharedOrderElementByLines(orderElement);
            } else {
                this.orderElement = null;
            }
        }
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "date cannot be empty if it is shared by lines")
    public boolean isDateMustBeNotNullIfIsSharedByLinesConstraint() {
        if (!firstLevelValidationsPassed()) {
            return true;
        }

        if (workReportType.getDateIsSharedByLines()) {
            return (getDate() != null);
        }
        return true;
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "resource cannot be empty if it is shared by lines")
    public boolean isResourceMustBeNotNullIfIsSharedByLinesConstraint() {
        if (!firstLevelValidationsPassed()) {
            return true;
        }

        if (workReportType.getResourceIsSharedInLines()) {
            return (getResource() != null);
        }
        return true;
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "task cannot be empty if it is shared by lines")
    public boolean isOrderElementMustBeNotNullIfIsSharedByLinesConstraint() {
        if (!firstLevelValidationsPassed()) {
            return true;
        }

        if (workReportType.getOrderElementIsSharedInLines()) {
            return (getOrderElement() != null);
        }
        return true;
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "label type:the timesheet have not assigned this label type")
    public boolean isAssignedLabelTypesConstraint() {
        if (this.workReportType == null) {
            return true;
        }

        if (this.workReportType.getHeadingLabels().size() != this.labels.size()) {
            return false;
        }

        for (WorkReportLabelTypeAssigment typeAssigment : this.workReportType
                .getHeadingLabels()) {
            try {
                getLabelByType(typeAssigment.getLabelType());
            } catch (InstanceNotFoundException e) {
                return false;
            }
        }
        return true;
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "description value: the timesheet has some description field missing")
    public boolean isAssignedDescriptionValuesConstraint() {
        if (this.workReportType == null) {
            return true;
        }

        if (this.workReportType.getHeadingFields().size() > this.descriptionValues
                .size()) {
            return false;
        }

        for(DescriptionField field : this.workReportType.getHeadingFields()){
            try{
                getDescriptionValueByFieldName(field.getFieldName());
            }
            catch(InstanceNotFoundException e){
                return false;
            }
        }
        return true;
    }

    @SuppressWarnings("unused")
    @AssertTrue(message = "There are repeated description values in the timesheet ")
    public boolean isAssignedRepeatedDescriptionValuesConstraint() {

        Set<String> textFields = new HashSet<String>();

        for (DescriptionValue v : this.descriptionValues) {

            String name = v.getFieldName();

            if (!StringUtils.isBlank(name)) {
                if (textFields.contains(name.toLowerCase())) {
                    return false;
                } else {
                    textFields.add(name.toLowerCase());
                }
            }
        }
        return true;
    }

    public DescriptionValue getDescriptionValueByFieldName(String fieldName)
            throws InstanceNotFoundException {

        if (StringUtils.isBlank(fieldName)) {
            throw new InstanceNotFoundException(fieldName,
                    DescriptionValue.class.getName());
        }

        for (DescriptionValue v : this.descriptionValues) {
            if (v.getFieldName().equalsIgnoreCase(StringUtils.trim(fieldName))) {
                return v;
            }
        }

        throw new InstanceNotFoundException(fieldName, DescriptionValue.class
                .getName());
    }

    public Label getLabelByType(LabelType type)
            throws InstanceNotFoundException {
        Validate.notNull(type);

        for (Label l : this.labels) {
            if (l.getType().getId().equals(type.getId())) {
                return l;
            }
        }

        throw new InstanceNotFoundException(type, LabelType.class.getName());
    }

    private void updateItsFieldsAndLabels(WorkReportType workReportType) {
        assignItsDescriptionValues(workReportType);
        assignItsLabels(workReportType);

        // it updates the fields and labels of its timesheet lines
        for (WorkReportLine line : getWorkReportLines()) {
            line.updateItsFieldsAndLabels();
        }
    }

    private void assignItsLabels(WorkReportType workReportType){
        if (workReportType != null) {
            labels.clear();
            for (WorkReportLabelTypeAssigment labelTypeAssigment : workReportType.getHeadingLabels()) {
                labels.add(labelTypeAssigment.getDefaultLabel());
            }
        }
    }

    private void assignItsDescriptionValues(WorkReportType workReportType) {
        if (workReportType != null) {
            descriptionValues.clear();
            for (DescriptionField descriptionField : workReportType
                    .getHeadingFields()) {
                DescriptionValue descriptionValue = DescriptionValue.create(
                        descriptionField.getFieldName(), null);
                descriptionValues.add(descriptionValue);
            }
        }
    }

    private void updateSharedDateByLines(Date date) {
        for (WorkReportLine line : getWorkReportLines()) {
            line.updateSharedDateByLines();
        }
    }

    private void updateSharedResourceByLines(Resource resource) {
        for (WorkReportLine line : getWorkReportLines()) {
            line.updateSharedResourceByLines();
        }
    }

    private void updateSharedOrderElementByLines(OrderElement orderElement) {
        for (WorkReportLine line : getWorkReportLines()) {
            line.updateSharedOrderElementByLines();
        }
    }

    @Override
    protected IWorkReportDAO getIntegrationEntityDAO() {
        return Registry.getWorkReportDAO();
    }

    private boolean firstLevelValidationsPassed() {
        return (workReportType != null);
    }

    public WorkReportLine getWorkReportLineByCode(String code)
            throws InstanceNotFoundException {

        if (StringUtils.isBlank(code)) {
            throw new InstanceNotFoundException(code, WorkReportLine.class
                    .getName());
        }

        for (WorkReportLine l : this.workReportLines) {
            if (l.getCode().equalsIgnoreCase(StringUtils.trim(code))) {
                return l;
            }
        }

        throw new InstanceNotFoundException(code, WorkReportLine.class
                .getName());

    }

    @AssertTrue(message = "The timesheet line codes must be unique.")
    public boolean isNonRepeatedWorkReportLinesCodesConstraint() {
        return getFirstRepeatedCode(this.workReportLines) == null;
    }

    public void generateWorkReportLineCodes(int numberOfDigits) {
        for (WorkReportLine line : this.getWorkReportLines()) {
            if ((line.getCode() == null) || (line.getCode().isEmpty())
                    || (!line.getCode().startsWith(this.getCode()))) {
                this.incrementLastWorkReportLineSequenceCode();
                String lineCode = EntitySequence.formatValue(numberOfDigits,
                        this.getLastWorkReportLineSequenceCode());
                line.setCode(this.getCode()
                        + EntitySequence.CODE_SEPARATOR_CHILDREN + lineCode);
            }
        }
    }

    public void incrementLastWorkReportLineSequenceCode() {
        if(lastWorkReportLineSequenceCode==null){
            lastWorkReportLineSequenceCode = 0;
        }
        lastWorkReportLineSequenceCode++;
    }

    @NotNull(message = "last timesheet line sequence code not specified")
    public Integer getLastWorkReportLineSequenceCode() {
        return lastWorkReportLineSequenceCode;
    }

    public EffortDuration getTotalEffortDuration() {
        EffortDuration result = EffortDuration.zero();
        for (WorkReportLine line : workReportLines) {
            result = result.plus(line.getEffort());
        }
        return result;
    }

    @AssertTrue(message = "only one timesheet line per day and task is allowed in personal timesheets")
    public boolean isOnlyOneWorkReportLinePerDayAndOrderElementInPersonalTimesheetConstraint() {
        if (!getWorkReportType().isPersonalTimesheetsType()) {
            return true;
        }

        Map<OrderElement, Set<LocalDate>> map = new HashMap<OrderElement, Set<LocalDate>>();
        for (WorkReportLine line : workReportLines) {
            OrderElement orderElement = line.getOrderElement();
            if (map.get(orderElement) == null) {
                map.put(orderElement, new HashSet<LocalDate>());
            }

            LocalDate date = LocalDate.fromDateFields(line.getDate());
            if (map.get(orderElement).contains(date)) {
                return false;
            }
            map.get(orderElement).add(date);
        }
        return true;
    }

    @AssertTrue(message = "In personal timesheets, all timesheet lines should be in the same period")
    public boolean isAllWorkReportLinesInTheSamePeriodInPersonalTimesheetConstraint() {
        if (!getWorkReportType().isPersonalTimesheetsType()) {
            return true;
        }

        if (workReportLines.isEmpty()) {
            return true;
        }

        LocalDate workReportDate = LocalDate.fromDateFields(workReportLines
                .iterator().next().getDate());
        PersonalTimesheetsPeriodicityEnum periodicity = Registry
                .getConfigurationDAO()
                .getConfigurationWithReadOnlyTransaction()
                .getPersonalTimesheetsPeriodicity();
        LocalDate min = periodicity.getStart(workReportDate);
        LocalDate max = periodicity.getEnd(workReportDate);

        for (WorkReportLine line : workReportLines) {
            LocalDate date = LocalDate.fromDateFields(line.getDate());
            if ((date.compareTo(min) < 0) || (date.compareTo(max) > 0)) {
                return false;
            }
        }
        return true;
    }

    @AssertTrue(message = "resource has to be bound to a user in personal timesheets")
    public boolean isResourceIsBoundInPersonalTimesheetConstraint() {
        if (!getWorkReportType().isPersonalTimesheetsType()) {
            return true;
        }

        if (resource != null) {
            try {
                Worker worker = Registry.getWorkerDAO().find(resource.getId());
                return worker.getUser() != null;
            } catch (InstanceNotFoundException e) {
                // Do nothing
            }
        }

        return false;
    }

    @AssertTrue(message = "the same task is marked as finished by more than one timesheet line")
    public boolean isSameOrderElementFinishedBySeveralWorkReportLinesConstraint() {
        Set<OrderElement> finishedOrderElements = new HashSet<OrderElement>();

        for (WorkReportLine line : workReportLines) {
            if (line.isFinished()) {
                if (Util.contains(finishedOrderElements, line.getOrderElement())) {
                    return false;
                }
                finishedOrderElements.add(line.getOrderElement());
            }
        }

        return true;
    }

    public boolean isFinished(OrderElement orderElement) {
        for (WorkReportLine line : workReportLines) {
            if (line.isFinished()
                    && Util.equals(line.getOrderElement(), orderElement)) {
                return true;
            }
        }
        return false;
    }

}
TOP

Related Classes of org.libreplan.business.workreports.entities.WorkReport

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.