Calculate progress and hours bars always proportionally to task size

Both bars will work like the money cost bar was already working.

The change is done due to the problem that appears when you adapt the planning,
and some planning remains before the start of the task. In that cases the bars
were not being printed properly.

Moreover current implementation was quite complex, and even if it gives some
useful information in specific cases, it also causes some misunderstandings to
the users.

FEA: ItEr77S12AdaptPlanningAccordingTimesheets
This commit is contained in:
Manuel Rego Casasnovas 2012-11-19 13:57:20 +01:00
parent babe242b52
commit 872520dac2
5 changed files with 31 additions and 209 deletions

View file

@ -520,7 +520,7 @@ public class TaskComponent extends Div implements AfterCompose {
int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthHoursAdvancePercentage = pixelsFromStartUntil(
startPixels,
this.task.getHoursAdvanceEndDate()) + "px";
this.task.getHoursAdvanceBarEndDate()) + "px";
response(null, new AuInvoke(this, "resizeCompletionAdvance",
widthHoursAdvancePercentage));
@ -573,7 +573,7 @@ public class TaskComponent extends Div implements AfterCompose {
if (task.isShowingAdvances()) {
int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthAdvancePercentage = pixelsFromStartUntil(startPixels,
this.task.getAdvanceEndDate()) + "px";
this.task.getAdvanceBarEndDate()) + "px";
response(null, new AuInvoke(this, "resizeCompletion2Advance",
widthAdvancePercentage));
} else {
@ -587,7 +587,7 @@ public class TaskComponent extends Div implements AfterCompose {
int startPixels = this.task.getBeginDate().toPixels(getMapper());
String widthAdvancePercentage = pixelsFromStartUntil(startPixels,
this.task.getAdvanceEndDate(progressType)) + "px";
this.task.getAdvanceBarEndDate(progressType)) + "px";
response(null, new AuInvoke(this, "resizeCompletion2Advance",
widthAdvancePercentage));
} else {

View file

@ -174,7 +174,7 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
}
@Override
public GanttDate getHoursAdvanceEndDate() {
public GanttDate getHoursAdvanceBarEndDate() {
return GanttDate.createFrom(new Date(hoursAdvanceEndDate));
}
@ -189,13 +189,13 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
}
@Override
public GanttDate getAdvanceEndDate() {
public GanttDate getAdvanceBarEndDate() {
return advanceEndDate != null ? GanttDate.createFrom(new Date(
advanceEndDate.getTime()))
: null;
}
@Override
public BigDecimal getHoursAdvancePercentage() {
public BigDecimal getHoursAdvanceBarPercentage() {
return hoursAdvancePercentage;
}
@ -284,7 +284,7 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
}
@Override
public GanttDate getAdvanceEndDate(String progressType) {
public GanttDate getAdvanceBarEndDate(String progressType) {
return null;
}

View file

@ -75,15 +75,15 @@ public interface ITaskFundamentalProperties {
public void setNotes(String notes);
public GanttDate getHoursAdvanceEndDate();
public GanttDate getHoursAdvanceBarEndDate();
public GanttDate getMoneyCostBarEndDate();
BigDecimal getMoneyCostBarPercentage();
public GanttDate getAdvanceEndDate();
public GanttDate getAdvanceBarEndDate();
public BigDecimal getHoursAdvancePercentage();
public BigDecimal getHoursAdvanceBarPercentage();
public BigDecimal getAdvancePercentage();
@ -115,7 +115,7 @@ public interface ITaskFundamentalProperties {
public List<Constraint<GanttDate>> getCurrentLengthConstraint();
public GanttDate getAdvanceEndDate(String progressType);
public GanttDate getAdvanceBarEndDate(String progressType);
String updateTooltipText(String progressType);

View file

@ -384,8 +384,8 @@ public abstract class Task implements ITaskFundamentalProperties {
}
@Override
public BigDecimal getHoursAdvancePercentage() {
return fundamentalProperties.getHoursAdvancePercentage();
public BigDecimal getHoursAdvanceBarPercentage() {
return fundamentalProperties.getHoursAdvanceBarPercentage();
}
@Override
@ -394,8 +394,8 @@ public abstract class Task implements ITaskFundamentalProperties {
}
@Override
public GanttDate getHoursAdvanceEndDate() {
return fundamentalProperties.getHoursAdvanceEndDate();
public GanttDate getHoursAdvanceBarEndDate() {
return fundamentalProperties.getHoursAdvanceBarEndDate();
}
@Override
@ -409,12 +409,12 @@ public abstract class Task implements ITaskFundamentalProperties {
}
@Override
public GanttDate getAdvanceEndDate() {
return fundamentalProperties.getAdvanceEndDate();
public GanttDate getAdvanceBarEndDate() {
return fundamentalProperties.getAdvanceBarEndDate();
}
public GanttDate getAdvanceEndDate(String progressType) {
return fundamentalProperties.getAdvanceEndDate(progressType);
public GanttDate getAdvanceBarEndDate(String progressType) {
return fundamentalProperties.getAdvanceBarEndDate(progressType);
}
public String getTooltipText() {

View file

@ -21,10 +21,6 @@
package org.libreplan.web.planner;
import static org.libreplan.business.workingday.EffortDuration.fromHoursAsBigDecimal;
import static org.libreplan.business.workingday.EffortDuration.min;
import static org.libreplan.business.workingday.EffortDuration.seconds;
import static org.libreplan.business.workingday.EffortDuration.zero;
import static org.libreplan.web.I18nHelper._;
import static org.zkoss.ganttz.data.constraint.ConstraintOnComparableValues.biggerOrEqualThan;
import static org.zkoss.ganttz.data.constraint.ConstraintOnComparableValues.equalTo;
@ -39,8 +35,6 @@ import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
@ -86,7 +80,6 @@ import org.libreplan.business.resources.entities.Criterion;
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.EffortDuration.IEffortFrom;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.business.workingday.IntraDayDate.PartialDay;
import org.libreplan.web.common.Util;
@ -552,43 +545,12 @@ public class TaskElementAdapter {
}
@Override
public GanttDate getHoursAdvanceEndDate() {
OrderElement orderElement = taskElement.getOrderElement();
EffortDuration assignedEffort = EffortDuration.zero();
if (orderElement.getSumChargedEffort() != null) {
assignedEffort = orderElement.getSumChargedEffort()
.getTotalChargedEffort();
}
GanttDate result = null;
if (!(taskElement instanceof TaskGroup)) {
result = calculateLimitDateByHours(assignedEffort
.toHoursAsDecimalWithScale(2));
}
if (result == null) {
EffortDuration effort = taskElement.getSumOfAssignedEffort();
if (effort.isZero()) {
effort = EffortDuration.hours(orderElement.getWorkHours());
if (effort.isZero()) {
return getBeginDate();
}
}
BigDecimal percentage = new BigDecimal(assignedEffort
.divivedBy(effort).doubleValue()).setScale(2,
RoundingMode.HALF_UP);
result = calculateLimitDateByPercentage(percentage);
}
return result;
public GanttDate getHoursAdvanceBarEndDate() {
return calculateLimitDateProportionalToTaskElementSize(getHoursAdvanceBarPercentage());
}
@Override
public BigDecimal getHoursAdvancePercentage() {
public BigDecimal getHoursAdvanceBarPercentage() {
OrderElement orderElement = taskElement.getOrderElement();
if (orderElement == null) {
return BigDecimal.ZERO;
@ -694,22 +656,22 @@ public class TaskElementAdapter {
}
@Override
public GanttDate getAdvanceEndDate(String progressType) {
return getAdvanceEndDate(ProgressType.asEnum(progressType));
public GanttDate getAdvanceBarEndDate(String progressType) {
return getAdvanceBarEndDate(ProgressType.asEnum(progressType));
}
private GanttDate getAdvanceEndDate(ProgressType progressType) {
private GanttDate getAdvanceBarEndDate(ProgressType progressType) {
BigDecimal advancePercentage = BigDecimal.ZERO;
if (taskElement.getOrderElement() != null) {
advancePercentage = taskElement
.getAdvancePercentage(progressType);
}
return getAdvanceEndDate(advancePercentage);
return getAdvanceBarEndDate(advancePercentage);
}
@Override
public GanttDate getAdvanceEndDate() {
return getAdvanceEndDate(getAdvancePercentage());
public GanttDate getAdvanceBarEndDate() {
return getAdvanceBarEndDate(getAdvancePercentage());
}
private boolean isTaskRoot(TaskElement taskElement) {
@ -728,148 +690,8 @@ public class TaskElementAdapter {
});
}
private GanttDate getAdvanceEndDate(BigDecimal advancePercentage) {
if (advancePercentage.compareTo(BigDecimal.ONE) == 0) {
return getEndDate();
}
BigDecimal hours = BigDecimal.ZERO;
if (taskElement instanceof TaskGroup) {
//progess calculation for TaskGroups is done with
//this method, which is much lighter
return calculateLimitDateByPercentage(advancePercentage);
}
if (taskElement.getOrderElement() != null) {
hours = taskElement.getSumOfAssignedEffort()
.toHoursAsDecimalWithScale(2);
}
// Calculate date according to advanceHours or advancePercentage
final BigDecimal advanceHours = advancePercentage
.multiply(hours);
GanttDate result = calculateLimitDateByHours(advanceHours);
if (result == null) {
result = calculateLimitDateByPercentage(advancePercentage);
} else {
GanttDate endDate = toGantt(taskElement.getIntraDayEndDate());
if (result.compareTo(endDate) > 0) {
//don't allow progress bars wider than the task itself
result = endDate;
}
}
return result;
}
private GanttDate calculateLimitDateByPercentage(BigDecimal advancePercentage) {
BaseCalendar calendar = taskElement.getCalendar();
if (advancePercentage.compareTo(BigDecimal.ZERO) == 0
|| calendar == null) {
return getBeginDate();
}
IntraDayDate start = taskElement.getIntraDayStartDate();
IntraDayDate end = taskElement.getIntraDayEndDate();
int daysBetween = start.numberOfDaysUntil(end);
if (daysBetween == 0) {
return calculateLimitDateWhenDaysBetweenAreZero(advancePercentage);
}
BigDecimal daysAdvance = advancePercentage
.multiply(new BigDecimal(daysBetween));
int days = daysAdvance.intValue();
LocalDate advanceDate = taskElement.getStartAsLocalDate()
.plusDays(days);
EffortDuration capacity = calendar.getCapacityOn(PartialDay
.wholeDay(advanceDate));
int seconds = daysAdvance.subtract(new BigDecimal(days))
.multiply(new BigDecimal(capacity.getSeconds()))
.intValue();
return toGantt(IntraDayDate.create(advanceDate,
EffortDuration.seconds(seconds)));
}
private GanttDate calculateLimitDateWhenDaysBetweenAreZero(
BigDecimal advancePercentage) {
IntraDayDate start = taskElement.getIntraDayStartDate();
IntraDayDate end = taskElement.getIntraDayEndDate();
final BaseCalendar calendar = taskElement.getCalendar();
Iterable<PartialDay> daysUntil = start.daysUntil(end);
EffortDuration total = EffortDuration.sum(daysUntil,
new IEffortFrom<PartialDay>() {
@Override
public EffortDuration from(PartialDay each) {
return calendar.getCapacityOn(each);
}
});
BigDecimal totalAsSeconds = new BigDecimal(total.getSeconds());
EffortDuration advanceLeft = seconds(advancePercentage
.multiply(totalAsSeconds).intValue());
for (PartialDay each : daysUntil) {
if (advanceLeft.compareTo(calendar.getCapacityOn(each)) <= 0) {
LocalDate dayDate = each.getStart().getDate();
if (dayDate.equals(start.getDate())) {
return toGantt(IntraDayDate
.create(dayDate, advanceLeft.plus(start
.getEffortDuration())));
}
return toGantt(IntraDayDate
.create(dayDate, advanceLeft));
}
advanceLeft = advanceLeft.minus(calendar
.getCapacityOn(each));
}
return toGantt(end);
}
private GanttDate calculateLimitDateByHours(BigDecimal hours) {
if (hours == null || hours.compareTo(BigDecimal.ZERO) == 0) {
return null;
}
EffortDuration hoursLeft = fromHoursAsBigDecimal(hours);
IntraDayDate result = null;
EffortDuration effortLastDayNotZero = zero();
Map<LocalDate, EffortDuration> daysMap = taskElement
.getDurationsAssignedByDay();
if (daysMap.isEmpty()) {
return null;
}
for (Entry<LocalDate, EffortDuration> entry : daysMap
.entrySet()) {
if (!entry.getValue().isZero()) {
effortLastDayNotZero = entry.getValue();
}
EffortDuration decrement = min(entry.getValue(), hoursLeft);
hoursLeft = hoursLeft.minus(decrement);
if (hoursLeft.isZero()) {
result = IntraDayDate.create(entry.getKey(),
decrement);
break;
} else {
result = IntraDayDate.startOfDay(entry.getKey()
.plusDays(1));
}
}
if (!hoursLeft.isZero() && effortLastDayNotZero.isZero()) {
LOG.warn("limit not reached and no day with effort not zero");
}
if (!hoursLeft.isZero() && !effortLastDayNotZero.isZero()) {
while (!hoursLeft.isZero()) {
hoursLeft = hoursLeft.minus(min(effortLastDayNotZero,
hoursLeft));
result = result.nextDayAtStart();
}
}
if (result == null) {
return null;
}
return toGantt(result);
private GanttDate getAdvanceBarEndDate(BigDecimal advancePercentage) {
return calculateLimitDateProportionalToTaskElementSize(advancePercentage);
}
@Override
@ -1057,7 +879,7 @@ public class TaskElementAdapter {
.append("% , ");
result.append(_("Hours invested") + ": ")
.append(getHoursAdvancePercentage().multiply(
.append(getHoursAdvanceBarPercentage().multiply(
new BigDecimal(100))).append("% <br/>");
if (taskElement.getOrderElement() instanceof Order) {