net.rrm.ehour.timesheet.service.TimesheetPersistance.java Source code

Java tutorial

Introduction

Here is the source code for net.rrm.ehour.timesheet.service.TimesheetPersistance.java

Source

/*
 * 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; either version 2
 * 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */

package net.rrm.ehour.timesheet.service;

import net.rrm.ehour.audit.annot.NonAuditable;
import net.rrm.ehour.data.DateRange;
import net.rrm.ehour.domain.ProjectAssignment;
import net.rrm.ehour.domain.TimesheetComment;
import net.rrm.ehour.domain.TimesheetEntry;
import net.rrm.ehour.domain.User;
import net.rrm.ehour.exception.OverBudgetException;
import net.rrm.ehour.mail.service.ProjectManagerNotifierService;
import net.rrm.ehour.persistence.timesheet.dao.TimesheetCommentDao;
import net.rrm.ehour.persistence.timesheet.dao.TimesheetDao;
import net.rrm.ehour.project.status.ProjectAssignmentStatus;
import net.rrm.ehour.project.status.ProjectAssignmentStatusService;
import net.rrm.ehour.util.DomainUtil;
import net.rrm.ehour.util.EhourConstants;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.joda.time.Interval;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import scala.collection.Seq;

import java.util.*;

@Service
public class TimesheetPersistance implements IPersistTimesheet, IDeleteTimesheetEntry {
    private static final Logger LOGGER = Logger.getLogger(TimesheetPersistance.class);

    private TimesheetDao timesheetDAO;
    private TimesheetCommentDao timesheetCommentDAO;
    private ProjectAssignmentStatusService projectAssignmentStatusService;
    private ProjectManagerNotifierService projectManagerNotifierService;
    private TimesheetLockService timesheetLockService;
    private ApplicationContext context;

    @Autowired
    public TimesheetPersistance(TimesheetDao timesheetDAO, TimesheetCommentDao timesheetCommentDAO,
            ProjectAssignmentStatusService projectAssignmentStatusService,
            ProjectManagerNotifierService projectManagerNotifierService, TimesheetLockService timesheetLockService,
            ApplicationContext context) {
        this.timesheetDAO = timesheetDAO;
        this.timesheetCommentDAO = timesheetCommentDAO;
        this.projectAssignmentStatusService = projectAssignmentStatusService;
        this.projectManagerNotifierService = projectManagerNotifierService;
        this.timesheetLockService = timesheetLockService;
        this.context = context;
    }

    @Transactional
    public void deleteAllTimesheetDataForUser(User user) {
        timesheetCommentDAO.deleteCommentsForUser(user.getUserId());

        if (user.getProjectAssignments() != null && user.getProjectAssignments().size() > 0) {
            timesheetDAO.deleteTimesheetEntries(DomainUtil.getIdsFromDomainObjects(user.getProjectAssignments()));
        }
    }

    @Transactional
    @Override
    public List<ProjectAssignmentStatus> persistTimesheetWeek(Collection<TimesheetEntry> timesheetEntries,
            TimesheetComment comment, DateRange weekRange, User forUser) {
        Map<ProjectAssignment, List<TimesheetEntry>> timesheetRows = getTimesheetAsRows(timesheetEntries);

        List<ProjectAssignmentStatus> errorStatusses = new ArrayList<>();

        Seq<Interval> lockedDatesInRange = timesheetLockService.findLockedDatesInRange(weekRange.getDateStart(),
                weekRange.getDateEnd(), forUser);
        List<Date> lockedDates = TimesheetLockService$.MODULE$.intervalToJavaDates(lockedDatesInRange);

        for (Map.Entry<ProjectAssignment, List<TimesheetEntry>> entry : timesheetRows.entrySet()) {
            try {
                getTimesheetPersister().validateAndPersist(entry.getKey(), entry.getValue(), weekRange,
                        lockedDates);
            } catch (OverBudgetException e) {
                errorStatusses.add(e.getStatus());
            }
        }

        // only update the comment when
        // - the whole week is not locked
        // - comment is an update
        // - or the comment is empty
        boolean wholeWeekLocked = TimesheetLockService$.MODULE$.isRangeLocked(weekRange.getDateStart(),
                weekRange.getDateEnd(), lockedDatesInRange);

        if (!wholeWeekLocked
                && (comment.getNewComment() == Boolean.FALSE || StringUtils.isNotBlank(comment.getComment()))) {
            timesheetCommentDAO.persist(comment);
        }

        return errorStatusses;
    }

    private IPersistTimesheet getTimesheetPersister() {
        return context.getBean(IPersistTimesheet.class);
    }

    private Map<ProjectAssignment, List<TimesheetEntry>> getTimesheetAsRows(Collection<TimesheetEntry> entries) {
        Map<ProjectAssignment, List<TimesheetEntry>> timesheetRows = new HashMap<>();

        for (TimesheetEntry timesheetEntry : entries) {
            ProjectAssignment assignment = timesheetEntry.getEntryId().getProjectAssignment();

            List<TimesheetEntry> assignmentEntries = (timesheetRows.containsKey(assignment))
                    ? timesheetRows.get(assignment)
                    : new ArrayList<TimesheetEntry>();

            assignmentEntries.add(timesheetEntry);

            timesheetRows.put(assignment, assignmentEntries);
        }

        return timesheetRows;
    }

    @Transactional(rollbackFor = OverBudgetException.class, propagation = Propagation.REQUIRES_NEW)
    @NonAuditable
    public void validateAndPersist(ProjectAssignment assignment, List<TimesheetEntry> entries, DateRange weekRange,
            List<Date> lockedDates) throws OverBudgetException {
        ProjectAssignmentStatus beforeStatus = projectAssignmentStatusService.getAssignmentStatus(assignment);

        boolean checkAfterStatus = beforeStatus.isValid();

        try {
            persistEntries(assignment, entries, weekRange, !beforeStatus.isValid(), lockedDates);
        } catch (OverBudgetException obe) {
            // make sure it's retrown by checking the after status
            checkAfterStatus = true;
        }

        ProjectAssignmentStatus afterStatus = projectAssignmentStatusService.getAssignmentStatus(assignment);

        if (checkAfterStatus && !afterStatus.isValid()) {
            throw new OverBudgetException(afterStatus);
        } else if (!beforeStatus.equals(afterStatus) && canNotifyPm(assignment)) {
            notifyPm(assignment, afterStatus);
        }
    }

    private void persistEntries(ProjectAssignment assignment, List<TimesheetEntry> entries, DateRange weekRange,
            boolean onlyLessThanExisting, List<Date> lockedDates) throws OverBudgetException {
        List<TimesheetEntry> previousEntries = timesheetDAO.getTimesheetEntriesInRange(assignment, weekRange);

        for (TimesheetEntry entry : entries) {
            if (!entry.getEntryId().getProjectAssignment().equals(assignment)) {
                LOGGER.error("Invalid entry in assignment list, skipping: " + entry);
                continue;
            }

            if (lockedDates.contains(entry.getEntryId().getEntryDate())) {
                LOGGER.error("Date is locked but still trying to update " + entry);

                previousEntries.remove(entry);
                continue;
            }

            if (entry.isEmptyEntry()) {
                deleteEntry(getEntry(previousEntries, entry));
            } else {
                persistEntry(onlyLessThanExisting, entry, getEntry(previousEntries, entry));
            }

            previousEntries.remove(entry);
        }

        removeOldEntries(previousEntries);
    }

    private void removeOldEntries(List<TimesheetEntry> previousEntries) {
        for (TimesheetEntry entry : previousEntries) {
            timesheetDAO.delete(entry);
        }
    }

    private void deleteEntry(TimesheetEntry existingEntry) {
        if (existingEntry != null) {
            timesheetDAO.delete(existingEntry);
        }
    }

    private void persistEntry(boolean bookOnlyLessHoursThanExistingHours, TimesheetEntry newEntry,
            TimesheetEntry existingEntry) throws OverBudgetException {
        if (bookOnlyLessHoursThanExistingHours
                && (existingEntry == null || (newEntry.getHours().compareTo(existingEntry.getHours()) > 0))) {
            throw new OverBudgetException();
        }

        newEntry.setUpdateDate(new Date());

        if (existingEntry != null) {
            timesheetDAO.merge(newEntry);
        } else {
            timesheetDAO.persist(newEntry);
        }
    }

    private TimesheetEntry getEntry(List<TimesheetEntry> entries, TimesheetEntry entry) {
        int index = entries.indexOf(entry);

        if (index >= 0) {
            return entries.get(index);
        } else {
            return null;
        }
    }

    private void notifyPm(ProjectAssignment assignment, ProjectAssignmentStatus status) {
        TimesheetEntry entry;

        entry = timesheetDAO.getLatestTimesheetEntryForAssignment(assignment.getAssignmentId());

        // over alloted - fixed
        if (assignment.getAssignmentType().getAssignmentTypeId() == EhourConstants.ASSIGNMENT_TIME_ALLOTTED_FIXED
                && status.getStatusses().contains(ProjectAssignmentStatus.Status.OVER_ALLOTTED)) {
            projectManagerNotifierService.mailPMFixedAllottedReached(status.getAggregate(),
                    entry.getEntryId().getEntryDate(), assignment.getProject().getProjectManager());
        }
        // over overrun - flex
        else if (assignment.getAssignmentType()
                .getAssignmentTypeId() == EhourConstants.ASSIGNMENT_TIME_ALLOTTED_FLEX
                && status.getStatusses().contains(ProjectAssignmentStatus.Status.OVER_OVERRUN)) {
            projectManagerNotifierService.mailPMFlexOverrunReached(status.getAggregate(),
                    entry.getEntryId().getEntryDate(), assignment.getProject().getProjectManager());
        }
        // in overrun - flex
        else if (status.getStatusses().contains(ProjectAssignmentStatus.Status.IN_OVERRUN) && assignment
                .getAssignmentType().getAssignmentTypeId() == EhourConstants.ASSIGNMENT_TIME_ALLOTTED_FLEX) {
            projectManagerNotifierService.mailPMFlexAllottedReached(status.getAggregate(),
                    entry.getEntryId().getEntryDate(), assignment.getProject().getProjectManager());
        }
    }

    private boolean canNotifyPm(ProjectAssignment assignment) {
        return assignment.isNotifyPm() && assignment.getProject().getProjectManager() != null
                && assignment.getProject().getProjectManager().getEmail() != null;

    }
}