/* * This file is part of LibrePlan * * Copyright (C) 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.planner.entities; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.HashMap; import java.util.List; import java.util.Map; import org.libreplan.business.costcategories.daos.IHourCostDAO; import org.libreplan.business.orders.entities.OrderElement; 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; /** * Class to calculate the money cost of a {@link TaskElement}.<br /> * * Money cost is calculated checking the hours reported for that task and using * the cost category of each resource in the different dates.<br /> * * Money cost is stored in a map that will be cached in memeroy. This map could * be reseted when needed with method {@code resetMoneyCostMap}. * * @author Manuel Rego Casasnovas <mrego@igalia.com> * @author Susana Montes Pedreira <smontes@wirelessgalicia.com> */ @Component @Scope(BeanDefinition.SCOPE_SINGLETON) public class MoneyCostCalculator implements IMoneyCostCalculator { @Autowired private IWorkReportLineDAO workReportLineDAO; @Autowired private IHourCostDAO hourCostDAO; private Map<OrderElement, MoneyCost> moneyCostTotalMap = new HashMap<OrderElement, MoneyCost>(); private class MoneyCost { private BigDecimal costOfHours; private BigDecimal costOfExpenses; public MoneyCost() { } public void setCostOfHours(BigDecimal costOfHours) { this.costOfHours = costOfHours; } public BigDecimal getCostOfHours() { return costOfHours; } public void setCostOfExpenses(BigDecimal costOfExpenses) { this.costOfExpenses = costOfExpenses; } public BigDecimal getCostOfExpenses() { return costOfExpenses; } } @Override public void resetMoneyCostMap() { moneyCostTotalMap = new HashMap<OrderElement, MoneyCost>(); } @Override public BigDecimal getTotalMoneyCost(OrderElement orderElement) { BigDecimal result = BigDecimal.ZERO.setScale(2); BigDecimal moneyCostOfHours = getHoursMoneyCost(orderElement); if (moneyCostOfHours != null) { result = result.add(moneyCostOfHours); } BigDecimal moneyCostOfExpenses = getExpensesMoneyCost(orderElement); if (moneyCostOfExpenses != null) { result = result.add(moneyCostOfExpenses); } if (result != null) { result = result.setScale(2, RoundingMode.HALF_UP); } return result; } @Override public BigDecimal getHoursMoneyCost(OrderElement orderElement) { MoneyCost moneyCost = moneyCostTotalMap.get(orderElement); if (moneyCost != null) { BigDecimal result = moneyCost.getCostOfHours(); if (result != null) { return result; } } BigDecimal result = BigDecimal.ZERO.setScale(2); for (OrderElement each : orderElement.getChildren()) { result = result.add(getHoursMoneyCost(each)); } result = result.add(getMoneyCostFromOwnWorkReportLines(orderElement)) .setScale(2, RoundingMode.HALF_UP); if (moneyCost == null) { moneyCost = new MoneyCost(); } moneyCost.setCostOfHours(result); moneyCostTotalMap.put(orderElement, moneyCost); return result; } private BigDecimal getMoneyCostFromOwnWorkReportLines(OrderElement orderElement) { List<WorkReportLine> workReportLines = workReportLineDAO .findByOrderElement(orderElement); BigDecimal result = BigDecimal.ZERO.setScale(2); for (WorkReportLine workReportLine : workReportLines) { BigDecimal priceCost = hourCostDAO .getPriceCostFromResourceDateAndType( workReportLine.getResource(), workReportLine.getLocalDate(), workReportLine.getTypeOfWorkHours()); // If cost undefined via CostCategory get it from type if (priceCost == null) { priceCost = workReportLine.getTypeOfWorkHours() .getDefaultPrice(); } BigDecimal cost = priceCost.multiply(workReportLine.getEffort() .toHoursAsDecimalWithScale(2)); result = result.add(cost); } return result; } /** * Divides {@code moneyCost} by {@code budget} if {@code budget} is * different from 0. Otherwise, returns 0. * * @param moneyCost * @param budget * @return A BigDecimal from 0 to 1 with the proportion */ public static BigDecimal getMoneyCostProportion(BigDecimal moneyCost, BigDecimal budget) { if (budget.compareTo(BigDecimal.ZERO) == 0) { return BigDecimal.ZERO; } return moneyCost.divide(budget, 2, RoundingMode.HALF_UP); } @Override public BigDecimal getExpensesMoneyCost(OrderElement orderElement) { MoneyCost moneyCost = moneyCostTotalMap.get(orderElement); if (moneyCost != null) { BigDecimal result = moneyCost.getCostOfExpenses(); if (result != null) { return result; } } BigDecimal result = BigDecimal.ZERO.setScale(2); if ((orderElement.getSumExpenses()) != null) { result = result.add(orderElement.getSumExpenses().getTotalDirectExpenses()); result = result.add(orderElement.getSumExpenses().getTotalIndirectExpenses()).setScale( 2, RoundingMode.HALF_UP); } if (moneyCost == null) { moneyCost = new MoneyCost(); } moneyCost.setCostOfExpenses(result); moneyCostTotalMap.put(orderElement, moneyCost); return result; } }