org.libreplan.business.planner.entities.HoursCostCalculator.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.business.planner.entities.HoursCostCalculator.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2011 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.planner.entities;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.sql.Time;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.SortedMap;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.Date;

import org.joda.time.LocalDate;
import org.joda.time.LocalTime;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.planner.entities.DayAssignment.FilterType;
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
import org.libreplan.business.workreports.entities.WorkReportLine;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

/**
 * Cost calulator in terms of hours.
 *
 * @author Manuel Rego Casasnovas <mrego@igalia.com>
 * @author Vova Perebykivskyi <vova@libreplan-enterprise.com>
 */
@Component
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class HoursCostCalculator implements ICostCalculator {

    @Autowired
    private IWorkReportLineDAO workReportLineDAO;

    @Override
    public SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task) {
        return getAdvanceCost(task, null, null);
    }

    @Override
    public SortedMap<LocalDate, BigDecimal> getAdvanceCost(Task task, LocalDate filterStartDate,
            LocalDate filterEndDate) {
        DirectAdvanceAssignment advanceAssignment = (task.getOrderElement() != null)
                ? task.getOrderElement().getReportGlobalAdvanceAssignment()
                : null;

        if (advanceAssignment == null) {
            return new TreeMap<>();
        }

        return calculateHoursPerDay(task.getHoursSpecifiedAtOrder(), advanceAssignment.getAdvanceMeasurements(),
                filterStartDate, filterEndDate);
    }

    private SortedMap<LocalDate, BigDecimal> calculateHoursPerDay(Integer totalHours,
            SortedSet<AdvanceMeasurement> advanceMeasurements, LocalDate filterStartDate, LocalDate filterEndDate) {

        SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();

        for (AdvanceMeasurement advanceMeasurement : advanceMeasurements) {
            LocalDate day = advanceMeasurement.getDate();
            if (((filterStartDate == null) || day.compareTo(filterStartDate) >= 0)
                    && ((filterEndDate == null) || day.compareTo(filterEndDate) <= 0)) {

                BigDecimal cost = advanceMeasurement.getValue().setScale(2).multiply(new BigDecimal(totalHours))
                        .divide(new BigDecimal(100), new MathContext(2, RoundingMode.HALF_UP));
                result.put(day, cost);
            }
        }

        return result;
    }

    @Override
    public SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task) {
        return getEstimatedCost(task, null, null);
    }

    /**
     * BCWS values are calculating here.
     * MAX(BCWS) equals addition of all dayAssignments.
     */
    @Override
    public SortedMap<LocalDate, BigDecimal> getEstimatedCost(Task task, LocalDate filterStartDate,
            LocalDate filterEndDate) {

        if (task.isSubcontracted()) {
            return getAdvanceCost(task);
        }

        SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();

        List<DayAssignment> dayAssignments = task.getDayAssignments(FilterType.WITHOUT_DERIVED);
        if (dayAssignments.isEmpty()) {
            return result;
        }

        int additionOfAllAssignmentsMinutes = 0;

        for (DayAssignment dayAssignment : dayAssignments) {
            LocalDate day = dayAssignment.getDay();
            if (((filterStartDate == null) || day.compareTo(filterStartDate) >= 0)
                    && ((filterEndDate == null) || day.compareTo(filterEndDate) <= 0)) {

                String currentTime = dayAssignment.getDuration().toFormattedString();

                SimpleDateFormat format1 = new SimpleDateFormat("hh:mm");
                SimpleDateFormat format2 = new SimpleDateFormat("hh");

                Date date = null;

                try {
                    if (isParsableWithFormat1(currentTime)) {
                        date = format1.parse(currentTime);
                    } else if (isParsableWithFormat2(currentTime)) {
                        date = format2.parse(currentTime);
                    }
                } catch (ParseException e) {
                    e.printStackTrace();
                }

                assert date != null;

                LocalTime time = new LocalTime(date.getTime());
                // Time time = new Time(date.getTime());

                BigDecimal hours = new BigDecimal(time.getHourOfDay());
                additionOfAllAssignmentsMinutes += time.getMinuteOfHour();

                if (!result.containsKey(day)) {
                    result.put(day, BigDecimal.ZERO);
                }

                /**
                 * On last day assignment app will check addition of minutes of all assignments.
                 * If it is between 30 and 60 - add 1 hour to the last value of result.
                 * If it is more than 60 then divide on 60 and calculate hours.
                 * E.G. 120 minutes / 60 = 2 hours.
                 */
                if (dayAssignment.equals(dayAssignments.get(dayAssignments.size() - 1))) {

                    if (additionOfAllAssignmentsMinutes >= 30 && additionOfAllAssignmentsMinutes <= 60)
                        hours = BigDecimal.valueOf(hours.intValue() + 1);

                    if (additionOfAllAssignmentsMinutes > 60)
                        hours = BigDecimal.valueOf(hours.intValue() + (additionOfAllAssignmentsMinutes / 60));
                }
                result.put(day, result.get(day).add(hours));
            }
        }
        return result;
    }

    private boolean isParsableWithFormat1(String input) {
        boolean parsable = true;
        try {
            SimpleDateFormat format = new SimpleDateFormat("hh:mm");
            format.parse(input);
        } catch (ParseException e) {
            parsable = false;
        }
        return parsable;
    }

    private boolean isParsableWithFormat2(String input) {
        boolean parsable = true;
        try {
            SimpleDateFormat format = new SimpleDateFormat("hh");
            format.parse(input);
        } catch (ParseException e) {
            parsable = false;
        }
        return parsable;
    }

    @Override
    public SortedMap<LocalDate, BigDecimal> getWorkReportCost(Task task) {
        if (task.isSubcontracted()) {
            return getAdvanceCost(task);
        }

        SortedMap<LocalDate, BigDecimal> result = new TreeMap<LocalDate, BigDecimal>();
        List<WorkReportLine> workReportLines = workReportLineDAO
                .findByOrderElementAndChildren(task.getOrderElement());

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

        for (WorkReportLine workReportLine : workReportLines) {
            LocalDate day = new LocalDate(workReportLine.getDate());
            BigDecimal cost = workReportLine.getEffort().toHoursAsDecimalWithScale(2);

            if (!result.containsKey(day)) {
                result.put(day, BigDecimal.ZERO);
            }
            result.put(day, result.get(day).add(cost));
        }

        return result;
    }

}