services.plugins.system.timesheet1.TimesheetLoadableObject.java Source code

Java tutorial

Introduction

Here is the source code for services.plugins.system.timesheet1.TimesheetLoadableObject.java

Source

/*! LICENSE
 *
 * Copyright (c) 2015, The Agile Factory SA and/or its affiliates. All rights
 * reserved.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 2 of the License.
 *
 * 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package services.plugins.system.timesheet1;

import java.lang.reflect.InvocationTargetException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.tuple.Pair;

import controllers.admin.UserManager;
import dao.pmo.ActorDao;
import dao.pmo.PortfolioEntryDao;
import dao.pmo.PortfolioEntryPlanningPackageDao;
import dao.timesheet.TimesheetDao;
import framework.services.plugins.loader.toolkit.ILoadableObject;
import framework.utils.Msg;
import models.framework_models.parent.IModelConstants;
import models.pmo.Actor;
import models.pmo.ActorType;
import models.pmo.OrgUnit;
import models.pmo.PortfolioEntry;
import models.pmo.PortfolioEntryPlanningPackage;
import models.timesheet.TimesheetEntry;
import models.timesheet.TimesheetLog;
import models.timesheet.TimesheetReport;
import models.timesheet.TimesheetReport.Status;
import models.timesheet.TimesheetReport.Type;
import play.data.Form;
import play.data.validation.Constraints.MaxLength;
import play.data.validation.Constraints.Required;
import play.data.validation.ValidationError;

/**
 * An object structure which is to be used to load timesheet data.<br/>
 * This structure is JAXB enabled so that it could support a direct XML load.
 * 
 * @author Pierre-Yves Cloux
 * @author Johann Kohler
 */
public class TimesheetLoadableObject implements ILoadableObject {
    private static final String DATE_FORMAT = "yyyy-MM-dd";

    private static Form<TimesheetLoadableObject> fakeFormTemplate = Form.form(TimesheetLoadableObject.class);

    private long sourceRowNumber;

    @Required(message = "governanceId must not be null or blank")
    @MaxLength(value = IModelConstants.SMALL_STRING)
    private String governanceId;

    @Required(message = "refId must not be null or blank")
    @MaxLength(value = IModelConstants.LARGE_STRING, message = "employeeRefId is too long "
            + IModelConstants.LARGE_STRING + " chars max")
    private String employeeRefId;

    @Required
    private String logDate;

    @Required
    private Double hours;

    @MaxLength(value = IModelConstants.MEDIUM_STRING, message = "packageRefId is too long "
            + IModelConstants.MEDIUM_STRING + " chars max")
    private String packageRefId;

    /**
     * Validate the non-string attributes.
     */
    public List<ValidationError> validate() {
        List<ValidationError> errors = new ArrayList<>();

        if (this.logDate != null && !this.logDate.equals("") && this.getLogDateAsDate() == null) {
            errors.add(new ValidationError("logDate",
                    "No valid timesheet date or invalid format (must be " + DATE_FORMAT + ")"));
        }

        if (this.governanceId != null && !this.governanceId.equals("") && this.getPortfolioEntry() == null) {
            errors.add(new ValidationError("governanceId",
                    String.format("GovernanceId %s does not exist", this.governanceId)));
        }

        if (this.employeeRefId != null && !this.employeeRefId.equals("") && this.getActor() == null) {
            errors.add(new ValidationError("employeeRefId",
                    String.format("EmployeeRefId %s does not exist", this.employeeRefId)));
        }

        if (this.packageRefId != null && !this.packageRefId.equals("") && this.getPlanningPackage() == null) {
            errors.add(new ValidationError("packageRefId",
                    String.format("Planning package %s does not exist", this.packageRefId)));
        }

        return errors.isEmpty() ? null : errors;
    }

    /**
     * Default constructor.
     */
    public TimesheetLoadableObject() {
    }

    /**
     * Look for a portfolio entry associated with the current governanceId
     * @return
     */
    public PortfolioEntry getPortfolioEntry() {
        return PortfolioEntryDao.getPEByGovernanceId(getGovernanceId());
    }

    /**
     * Look for an actor associated with the provided refId
     */
    public Actor getActor() {
        return ActorDao.getActorByRefId(getEmployeeRefId());
    }

    /**
     * Look for a planning package associated with the current portfolioEntry and planningPackageRefId
     */
    public PortfolioEntryPlanningPackage getPlanningPackage() {
        return PortfolioEntryPlanningPackageDao.getPEPlanningPackageByPEIdAndRefId(getPortfolioEntry().id,
                getPackageRefId());
    }

    @Override
    public Pair<Long, String> updateOrCreate() {
        PortfolioEntry pe = getPortfolioEntry();
        PortfolioEntryPlanningPackage pp = getPlanningPackage();
        Date logDateAsDate = getLogDateAsDate();
        Date startDate = getTimesheetReportStartDate();

        //Look for an existing TimesheetReport (if any)
        TimesheetReport tsr = TimesheetDao.getTimesheetReportByActorAndStartDate(getActor().id, startDate);
        TimesheetEntry tse = null;
        TimesheetLog tsLog = new TimesheetLog();
        if (tsr == null) {
            tsr = new TimesheetReport();
            tsr.startDate = startDate;
            tsr.type = Type.WEEKLY;
            tsr.status = Status.APPROVED;
            tsr.actor = getActor();
            tsr.orgUnit = tsr.actor.orgUnit;
            tsr.save();
        }

        //Look for an existing timesheet entry (if any)
        tse = TimesheetDao.getTimesheetEntryByPEandPEPlanningPackage(tsr.id, pe.id, pp != null ? pp.id : null);
        if (tse == null) {
            tse = new TimesheetEntry();
            tse.timesheetReport = tsr;
            tse.portfolioEntry = pe;
            tse.portfolioEntryPlanningPackage = pp;
            tse.save();
            addLogsToTimeSheetEntry(tse, startDate);
        }

        //Look for an existing timesheet log for the same day (then update it)
        if (tse.timesheetLogs != null) {
            for (TimesheetLog aLog : tse.timesheetLogs) {
                if (aLog.logDate.equals(logDateAsDate)) {
                    tsLog = aLog;
                }
            }
        }

        //Approve the report anyway
        tsr.status = Status.APPROVED;
        tsr.save();

        //The log of timesheet
        tsLog.timesheetEntry = tse;
        tsLog.logDate = logDateAsDate;
        tsLog.hours = tsLog.hours + this.hours;
        if (tsLog.hours < 0) {
            //Negative records are not allowed
            tsLog.hours = 0d;
        }
        tsLog.save();

        return Pair.of(tsLog.id, "Entry for " + tsLog.logDate);
    }

    /**
     * Validate the object consistency against various rules.<br/>
     * WARNING: these rules must be consistent with the {@link Actor} object as
     * well as {@link UserManager} ones. <br/>
     * This method also looks for {@link ActorType} and {@link OrgUnit}
     * according to the provided values.
     */
    public Pair<Boolean, String> validateAndComplete() {

        // Perform a validation using Play form features
        Form<TimesheetLoadableObject> fakeForm = null;

        try {
            Map<String, String> formData = BeanUtils.describe(this);
            fakeForm = fakeFormTemplate.bind(formData);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            throw new IllegalArgumentException("Unable to validate the structure of the object\n" + toString());
        }

        if (fakeForm.hasErrors()) {
            StringBuffer validationErrors = new StringBuffer();
            for (String fieldName : fakeForm.errors().keySet()) {
                validationErrors.append("Validation Error [").append(fieldName).append("]:");
                for (ValidationError error : fakeForm.errors().get(fieldName)) {
                    validationErrors.append('\t').append(Msg.get(error.message())).append('\n');
                }
            }
            String exceptionMessage = validationErrors.toString() + toString() + "\n";
            return Pair.of(false, exceptionMessage);
        }

        return Pair.of(true, "");
    }

    /**
     * Return the timesheet report start date matching with the current logDate
     * @return a timesheet report start date
     */
    private Date getTimesheetReportStartDate() {
        Calendar c = Calendar.getInstance();
        c.setTime(getLogDateAsDate());
        if (c.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
            if (c.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                c.add(Calendar.DAY_OF_WEEK, -1);
                c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            } else {
                c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
            }
        }
        return c.getTime();
    }

    /**
     * Add to the specified TimesheetEntry a list of TimesheetLog
     * following the specified start date (start date is MONDAY)
     * @param timesheetEntry
     * @param startDate
     */
    private void addLogsToTimeSheetEntry(TimesheetEntry timesheetEntry, Date startDate) {
        TimesheetLog tsLog = new TimesheetLog();
        tsLog.timesheetEntry = timesheetEntry;
        tsLog.hours = 0d;
        tsLog.logDate = startDate;
        tsLog.save();
        Calendar c = Calendar.getInstance();
        c.setTime(startDate);
        for (int i = 0; i < 6; i++) {
            tsLog = new TimesheetLog();
            c.add(Calendar.DATE, 1);
            tsLog.timesheetEntry = timesheetEntry;
            tsLog.hours = 0d;
            tsLog.logDate = c.getTime();
            tsLog.save();
        }
        timesheetEntry.refresh();
    }

    @Override
    public String toString() {
        return "TimesheetLoadableObject [sourceRowNumber=" + sourceRowNumber + ", governanceId=" + governanceId
                + ", employeeRefId=" + employeeRefId + ", logDate=" + logDate + ", hours=" + hours
                + ", packageRefId=" + packageRefId + "]";
    }

    @Override
    public long getSourceRowNumber() {
        return sourceRowNumber;
    }

    @Override
    public void setSourceRowNumber(long sourceRowNumber) {
        this.sourceRowNumber = sourceRowNumber;
    }

    public String getGovernanceId() {
        return governanceId;
    }

    public void setGovernanceId(String governanceId) {
        this.governanceId = governanceId;
    }

    public String getEmployeeRefId() {
        return employeeRefId;
    }

    public void setEmployeeRefId(String employeeRefId) {
        this.employeeRefId = employeeRefId;
    }

    public String getLogDate() {
        return logDate;
    }

    public Date getLogDateAsDate() {
        try {
            DateFormat format = new SimpleDateFormat(DATE_FORMAT);
            return format.parse(this.logDate);
        } catch (ParseException e) {
            return null;
        }
    }

    public void setLogDate(String logDateAsString) {
        this.logDate = logDateAsString;
    }

    public Double getHours() {
        return hours;
    }

    public void setHours(Double hours) {
        this.hours = hours;
    }

    public String getPackageRefId() {
        return packageRefId;
    }

    public void setPackageRefId(String packageRefId) {
        this.packageRefId = packageRefId;
    }

}