Implement money cost calculation in a new class called MoneyCostCalculator
Add a basic test to check that everything is working as expected FEA: ItEr76S17MoneyCostMonitoringSystem
This commit is contained in:
parent
27579c0bfd
commit
213e68c36e
5 changed files with 369 additions and 5 deletions
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* 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
|
||||
|
|
@ -21,20 +21,24 @@
|
|||
|
||||
package org.libreplan.business.costcategories.daos;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.Query;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.common.daos.IntegrationEntityDAO;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.costcategories.entities.HourCost;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
import org.libreplan.business.resources.entities.Resource;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Repository
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
|
|
@ -53,4 +57,25 @@ public class HourCostDAO extends IntegrationEntityDAO<HourCost> implements
|
|||
super.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getPriceCostFromResourceDateAndType(Resource resource,
|
||||
LocalDate date, TypeOfWorkHours type) {
|
||||
String strQuery = "SELECT hc.priceCost "
|
||||
+ "FROM ResourcesCostCategoryAssignment rcca, HourCost hc "
|
||||
+ "WHERE rcca.costCategory = hc.category "
|
||||
+ "AND rcca.resource = :resource " + "AND hc.type = :type "
|
||||
+ "AND rcca.initDate <= :date "
|
||||
+ "AND (rcca.endDate >= :date OR rcca.endDate IS NULL) "
|
||||
+ "AND hc.initDate <= :date "
|
||||
+ "AND (hc.endDate >= :date OR hc.endDate IS NULL)";
|
||||
|
||||
Query query = getSession().createQuery(strQuery);
|
||||
query.setParameter("resource", resource);
|
||||
query.setParameter("date", date);
|
||||
query.setParameter("type", type);
|
||||
|
||||
return (BigDecimal) query.uniqueResult();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2010-2011 Igalia, S.L.
|
||||
* 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
|
||||
|
|
@ -21,17 +21,43 @@
|
|||
|
||||
package org.libreplan.business.costcategories.daos;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.common.daos.IIntegrationEntityDAO;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.costcategories.entities.CostCategory;
|
||||
import org.libreplan.business.costcategories.entities.HourCost;
|
||||
import org.libreplan.business.costcategories.entities.ResourcesCostCategoryAssignment;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
import org.libreplan.business.resources.entities.Resource;
|
||||
|
||||
/**
|
||||
* @author Jacobo Aragunde Perez <jaragunde@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IHourCostDAO extends IIntegrationEntityDAO<HourCost> {
|
||||
|
||||
@Override
|
||||
public void remove(Long id) throws InstanceNotFoundException;
|
||||
|
||||
}
|
||||
/**
|
||||
* Returns the price cost of a {@link HourCost} associated with a
|
||||
* {@link Resource} in a specific {@link LocalDate} and with a concrete
|
||||
* {@link TypeOfWorkHours}<br />
|
||||
*
|
||||
* The association is done through {@link CostCategory} associated to the
|
||||
* resource in the specific date (from class
|
||||
* {@link ResourcesCostCategoryAssignment}).
|
||||
*
|
||||
* @param resource
|
||||
* @param date
|
||||
* @param type
|
||||
* @return A {@link BigDecimal} with the price cost for a {@link Resource}
|
||||
* in a {@link LocalDate} for this {@link TypeOfWorkHours}
|
||||
*/
|
||||
BigDecimal getPriceCostFromResourceDateAndType(Resource resource,
|
||||
LocalDate date, TypeOfWorkHours type);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 org.libreplan.business.orders.entities.OrderElement;
|
||||
|
||||
/**
|
||||
* Interface to calculate the money cost of a {@link TaskElement}.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
public interface IMoneyCostCalculator {
|
||||
|
||||
/**
|
||||
* Returns the money cost of a {@link TaskElement}.<br />
|
||||
*
|
||||
* It uses the {@link OrderElement} (or OrderElements) associated to the
|
||||
* {@link TaskElement} in order to calculate the cost using the following
|
||||
* formula:<br />
|
||||
* <tt>Sum of all the hours devoted to a task multiplied by the cost of
|
||||
* each hour according to these parameters (type of hour, cost category of
|
||||
* the resource, date of the work report)</tt>
|
||||
*
|
||||
* @param The
|
||||
* {@link TaskElement} to calculate the money cost
|
||||
* @return Money cost of the task
|
||||
*/
|
||||
BigDecimal getMoneyCost(TaskElement taskElement);
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* 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.List;
|
||||
|
||||
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}.
|
||||
*
|
||||
* Money cost is calculated checking the hours reported for that task and using
|
||||
* the cost category of each resource in the different dates.
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class MoneyCostCalculator implements IMoneyCostCalculator {
|
||||
|
||||
@Autowired
|
||||
private IWorkReportLineDAO workReportLineDAO;
|
||||
|
||||
@Autowired
|
||||
private IHourCostDAO hourCostDAO;
|
||||
|
||||
@Override
|
||||
public BigDecimal getMoneyCost(TaskElement taskElement) {
|
||||
OrderElement orderElement = taskElement.getOrderElement();
|
||||
|
||||
List<WorkReportLine> workReportLines = workReportLineDAO
|
||||
.findByOrderElementAndChildren(orderElement, false);
|
||||
|
||||
BigDecimal result = BigDecimal.ZERO.setScale(2);
|
||||
for (WorkReportLine workReportLine : workReportLines) {
|
||||
BigDecimal priceCost = hourCostDAO
|
||||
.getPriceCostFromResourceDateAndType(
|
||||
workReportLine.getResource(),
|
||||
workReportLine.getLocalDate(),
|
||||
workReportLine.getTypeOfWorkHours());
|
||||
BigDecimal cost = priceCost.multiply(workReportLine.getEffort()
|
||||
.toHoursAsDecimalWithScale(2));
|
||||
result = result.add(cost);
|
||||
}
|
||||
|
||||
return result.setScale(2, RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* 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.test.planner.entities;
|
||||
|
||||
import static org.easymock.EasyMock.expect;
|
||||
import static org.easymock.classextension.EasyMock.createNiceMock;
|
||||
import static org.easymock.classextension.EasyMock.replay;
|
||||
import static org.hamcrest.CoreMatchers.equalTo;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.libreplan.business.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_FILE;
|
||||
import static org.libreplan.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
|
||||
import org.libreplan.business.costcategories.daos.ICostCategoryDAO;
|
||||
import org.libreplan.business.costcategories.daos.ITypeOfWorkHoursDAO;
|
||||
import org.libreplan.business.costcategories.entities.CostCategory;
|
||||
import org.libreplan.business.costcategories.entities.HourCost;
|
||||
import org.libreplan.business.costcategories.entities.ResourcesCostCategoryAssignment;
|
||||
import org.libreplan.business.costcategories.entities.TypeOfWorkHours;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderLine;
|
||||
import org.libreplan.business.planner.entities.IMoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.MoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.TaskElement;
|
||||
import org.libreplan.business.resources.daos.IResourceDAO;
|
||||
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.daos.IWorkReportTypeDAO;
|
||||
import org.libreplan.business.workreports.entities.WorkReport;
|
||||
import org.libreplan.business.workreports.entities.WorkReportLine;
|
||||
import org.libreplan.business.workreports.entities.WorkReportType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
/**
|
||||
* Test for {@link MoneyCostCalculator}
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <mrego@igalia.com>
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE,
|
||||
BUSINESS_SPRING_CONFIG_TEST_FILE })
|
||||
@Transactional
|
||||
public class MoneyCostCalculatorTest {
|
||||
|
||||
@Autowired
|
||||
private IMoneyCostCalculator moneyCostCalculator;
|
||||
|
||||
@Autowired
|
||||
private IOrderElementDAO orderElementDAO;
|
||||
|
||||
@Autowired
|
||||
private IResourceDAO resourceDAO;
|
||||
|
||||
@Autowired
|
||||
private IWorkReportDAO workReportDAO;
|
||||
|
||||
@Autowired
|
||||
private IWorkReportTypeDAO workReportTypeDAO;
|
||||
|
||||
@Autowired
|
||||
private ICostCategoryDAO costCategoryDAO;
|
||||
|
||||
@Autowired
|
||||
private ITypeOfWorkHoursDAO typeOfWorkHoursDAO;
|
||||
|
||||
private TypeOfWorkHours typeOfWorkHours;
|
||||
private CostCategory costCategory;
|
||||
private Resource resource;
|
||||
private OrderElement orderElement;
|
||||
private WorkReportType workReportType;
|
||||
private WorkReport workReport;
|
||||
private TaskElement taskElement;
|
||||
|
||||
private void givenTypeOfWorkHours() {
|
||||
typeOfWorkHours = TypeOfWorkHours.createUnvalidated(
|
||||
"default-type-of-work-hours", "default-type-of-work-hours",
|
||||
true, new BigDecimal(30));
|
||||
typeOfWorkHoursDAO.save(typeOfWorkHours);
|
||||
}
|
||||
|
||||
private void givenCostCategory() {
|
||||
costCategory = CostCategory.createUnvalidated("default-cost-category",
|
||||
"default-cost-category", true);
|
||||
HourCost hourCost = HourCost.createUnvalidated(
|
||||
"default-hour-cost", new BigDecimal(50), new LocalDate());
|
||||
hourCost.setType(typeOfWorkHours);
|
||||
costCategory.addHourCost(hourCost);
|
||||
costCategoryDAO.save(costCategory);
|
||||
}
|
||||
|
||||
private void givenResource() {
|
||||
resource = Worker.createUnvalidated("default-resource",
|
||||
"default-resource", "default-resource", "default-resource");
|
||||
|
||||
ResourcesCostCategoryAssignment resourcesCostCategoryAssignment = ResourcesCostCategoryAssignment
|
||||
.create();
|
||||
resourcesCostCategoryAssignment
|
||||
.setCode("resources-cost-category-assignment");
|
||||
resourcesCostCategoryAssignment.setCostCategory(costCategory);
|
||||
resourcesCostCategoryAssignment.setInitDate(new LocalDate());
|
||||
|
||||
resource.addResourcesCostCategoryAssignment(resourcesCostCategoryAssignment);
|
||||
resourceDAO.save(resource);
|
||||
}
|
||||
|
||||
private void givenOrderElement() {
|
||||
orderElement = OrderLine
|
||||
.createOrderLineWithUnfixedPercentage(100);
|
||||
orderElement.setCode("default-order-element");
|
||||
orderElement.setName("default-order-element");
|
||||
orderElement.getHoursGroups().get(0).setCode("default-hours-group");
|
||||
orderElementDAO.save(orderElement);
|
||||
}
|
||||
|
||||
private void giveWorkReportType() {
|
||||
workReportType = WorkReportType.create("default-work-report-type",
|
||||
"default-work-report-type");
|
||||
workReportTypeDAO.save(workReportType);
|
||||
}
|
||||
|
||||
private void givenWorkReport() {
|
||||
workReport = WorkReport.create(workReportType);
|
||||
workReport.setCode("default-work-report");
|
||||
|
||||
WorkReportLine workReportLine = WorkReportLine.create(workReport);
|
||||
workReportLine.setCode("default-work-report-line");
|
||||
workReportLine.setDate(new Date());
|
||||
workReportLine.setResource(resource);
|
||||
workReportLine.setOrderElement(orderElement);
|
||||
workReportLine.setTypeOfWorkHours(typeOfWorkHours);
|
||||
workReportLine.setEffort(EffortDuration.hours(10));
|
||||
|
||||
workReport.addWorkReportLine(workReportLine);
|
||||
workReportDAO.save(workReport);
|
||||
}
|
||||
|
||||
private void givenTask() {
|
||||
taskElement = createNiceMock(TaskElement.class);
|
||||
expect(taskElement.getOrderElement()).andReturn(orderElement)
|
||||
.anyTimes();
|
||||
replay(taskElement);
|
||||
}
|
||||
|
||||
private void givenBasicExample() {
|
||||
givenTypeOfWorkHours();
|
||||
givenCostCategory();
|
||||
givenResource();
|
||||
givenOrderElement();
|
||||
giveWorkReportType();
|
||||
givenWorkReport();
|
||||
givenTask();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicTest() throws InstanceNotFoundException {
|
||||
givenBasicExample();
|
||||
assertThat(moneyCostCalculator.getMoneyCost(taskElement),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
}
|
||||
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue