diff --git a/libreplan-business/src/main/java/org/libreplan/business/resources/daos/IResourceLoadRatiosCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/resources/daos/IResourceLoadRatiosCalculator.java
new file mode 100644
index 000000000..d8e349625
--- /dev/null
+++ b/libreplan-business/src/main/java/org/libreplan/business/resources/daos/IResourceLoadRatiosCalculator.java
@@ -0,0 +1,80 @@
+/*
+ * 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 .
+ */
+
+package org.libreplan.business.resources.daos;
+
+import java.math.BigDecimal;
+
+import org.joda.time.LocalDate;
+import org.libreplan.business.resources.entities.Resource;
+import org.libreplan.business.scenarios.entities.Scenario;
+import org.libreplan.business.workingday.EffortDuration;
+
+/**
+ * Specifies the method to calculate the load ratios of a resource and the data
+ * type which represents the output
+ *
+ * @author Javier Moran Rua
+ *
+ */
+public interface IResourceLoadRatiosCalculator {
+
+ public interface ILoadRatiosDataType {
+
+ EffortDuration getLoad();
+
+ EffortDuration getOverload();
+
+ EffortDuration getCapacity();
+
+ /**
+ * Calculates the overtime ratio. The overtime ratio is defined as
+ * overload / (load+overload).
+ *
+ * @return the overtime ratio represented with a {@link BigDecimal} with
+ * scale of 2. If both load and overload are zero it is returned
+ * zero.
+ */
+ BigDecimal getOvertimeRatio();
+
+ /**
+ * Calculates the availability ratio. The availability ratio is defined
+ * as 1 - (load/capacity)*100. It is a percentage.
+ *
+ * @return the availability ratio represented with a {@link BigDecimal}
+ * with a scale of 2. In the case that the capacity is zero, a
+ * 0% of availability is returned.
+ */
+ BigDecimal getAvailiabilityRatio();
+ }
+
+ /**
+ * Calculates the load ratios of a resource between two dates in the
+ * escenario specified.
+ *
+ * @param resource
+ * @param startDate
+ * @param endDate
+ * @return the load ratios calculated.
+ */
+ ILoadRatiosDataType calculateLoadRatios(Resource resource,
+ LocalDate startDate,
+ LocalDate endDate, Scenario scenario);
+
+}
diff --git a/libreplan-business/src/main/java/org/libreplan/business/resources/daos/ResourceLoadRatiosCalculator.java b/libreplan-business/src/main/java/org/libreplan/business/resources/daos/ResourceLoadRatiosCalculator.java
new file mode 100644
index 000000000..cc34e34c4
--- /dev/null
+++ b/libreplan-business/src/main/java/org/libreplan/business/resources/daos/ResourceLoadRatiosCalculator.java
@@ -0,0 +1,218 @@
+/*
+ * 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 .
+ */
+
+package org.libreplan.business.resources.daos;
+
+import java.math.BigDecimal;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.joda.time.LocalDate;
+import org.libreplan.business.common.IAdHocTransactionService;
+import org.libreplan.business.common.IOnTransaction;
+import org.libreplan.business.planner.daos.IDayAssignmentDAO;
+import org.libreplan.business.planner.entities.DayAssignment;
+import org.libreplan.business.resources.entities.Resource;
+import org.libreplan.business.scenarios.entities.Scenario;
+import org.libreplan.business.workingday.EffortDuration;
+import org.libreplan.business.workingday.IntraDayDate.PartialDay;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.config.BeanDefinition;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Service;
+
+/**
+ * Class designed to be used as a singleton spring bean implementing the
+ * {@link IResourceLoadRatiosCalculator} interface.
+ *
+ * Spawns a new Hibernate transaction using {@link IAdHocTransactionService} to
+ * access the database.
+ *
+ * @author Javier Moran Rua
+ *
+ */
+
+@Service
+@Scope(BeanDefinition.SCOPE_SINGLETON)
+public class ResourceLoadRatiosCalculator implements
+ IResourceLoadRatiosCalculator {
+
+ @Autowired
+ private IDayAssignmentDAO dayAssigmentDAO;
+
+ @Autowired
+ private IResourceDAO resourceDAO;
+
+ @Autowired
+ private IAdHocTransactionService adHocTransactionService;
+
+ private static class LoadRatiosDataType implements
+ IResourceLoadRatiosCalculator.ILoadRatiosDataType {
+ private EffortDuration load;
+ private EffortDuration overload;
+ private EffortDuration capacity;
+
+ public LoadRatiosDataType(EffortDuration load, EffortDuration overload,
+ EffortDuration capacity) {
+ this.load = load;
+ this.overload = overload;
+ this.capacity = capacity;
+ }
+
+ @Override
+ public EffortDuration getLoad() {
+ return this.load;
+ }
+
+ @Override
+ public EffortDuration getOverload() {
+ return this.overload;
+ }
+
+ @Override
+ public EffortDuration getCapacity() {
+ return this.capacity;
+ }
+
+ @Override
+ public BigDecimal getOvertimeRatio() {
+ BigDecimal result;
+ if (this.load.isZero() && this.overload.isZero()) {
+ result = BigDecimal.ZERO;
+ } else {
+ result = this.overload.dividedByAndResultAsBigDecimal(this.load
+ .plus(this.capacity));
+ }
+
+ return result.setScale(2, BigDecimal.ROUND_HALF_UP);
+ }
+
+ @Override
+ public BigDecimal getAvailiabilityRatio() {
+ BigDecimal result;
+ if (this.capacity.isZero()) {
+ result = BigDecimal.ZERO;
+ } else {
+
+ result = BigDecimal.ONE.subtract(this.load
+ .dividedByAndResultAsBigDecimal(this.capacity));
+ if (result.compareTo(BigDecimal.ZERO) < 0) {
+ result = BigDecimal.ZERO;
+ }
+ }
+ return result.setScale(2, BigDecimal.ROUND_HALF_UP);
+ }
+ }
+
+ @Override
+ public ILoadRatiosDataType calculateLoadRatios(final Resource resource,
+ final LocalDate startDate, final LocalDate endDate,
+ final Scenario scenario) {
+
+ return adHocTransactionService
+ .runOnReadOnlyTransaction(new IOnTransaction() {
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public LoadRatiosDataType execute() {
+
+ resourceDAO.reattach(resource);
+
+ EffortDuration totalLoad = EffortDuration.zero(),
+ totalOverload = EffortDuration.zero(),
+ totalCapacity = EffortDuration.zero();
+
+ for (Map.Entry each :
+ getAllEffortPerDateFor(scenario,
+ startDate, endDate, resource)
+ .entrySet()) {
+ totalLoad = addLoad(totalLoad, each.getValue());
+ totalOverload = addOverload(totalOverload,
+ resource, each.getValue(), each.getKey());
+
+ }
+
+ totalCapacity = calculateTotalCapacity(resource,
+ startDate, endDate);
+ return new LoadRatiosDataType(totalLoad,
+ totalOverload, totalCapacity);
+ }
+
+ private Map
+ getAllEffortPerDateFor(Scenario scenario,LocalDate startDate,
+ LocalDate endDate, Resource resource) {
+
+ HashMap result =
+ new HashMap();
+
+ List l = dayAssigmentDAO.getAllFor(
+ scenario, startDate, endDate,
+ resource);
+
+ EffortDuration newValue = EffortDuration.zero();
+ for (DayAssignment each: l) {
+ if (result.containsKey(each.getDay())) {
+ newValue = result.get(each.getDay()).
+ plus(each.getDuration());
+ } else {
+ newValue = each.getDuration();
+ }
+ result.put(each.getDay(), newValue);
+ }
+ return result;
+ }
+
+ private EffortDuration addLoad(EffortDuration currentLoad,
+ EffortDuration load) {
+ return currentLoad.plus(load);
+ }
+
+ private EffortDuration calculateTotalCapacity(
+ Resource resource, LocalDate startDate,
+ LocalDate endDate) {
+
+ return resource.getCalendar().getWorkableDuration(
+ startDate, endDate);
+ }
+
+ private EffortDuration addOverload(
+ EffortDuration currentOverload, Resource resource,
+ EffortDuration loadAtDate, LocalDate date) {
+ EffortDuration result;
+ EffortDuration capacityAtDay = getCapacityAtDate(
+ resource, date);
+ if (capacityAtDay.compareTo(loadAtDate) < 0) {
+ result = currentOverload.plus(loadAtDate
+ .minus(capacityAtDay));
+ } else {
+ result = currentOverload;
+ }
+
+ return result;
+ }
+
+ private EffortDuration getCapacityAtDate(Resource resource,
+ LocalDate date) {
+ return resource.getCalendar().getCapacityOn(
+ PartialDay.wholeDay(date));
+ }
+ });
+ }
+}