Merge branch 'money-cost-monitoring-system'
This commit is contained in:
commit
979ac144b1
62 changed files with 1619 additions and 53 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
|
||||
|
|
@ -227,6 +227,7 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
}
|
||||
|
||||
result.setShowingReportedHours(planner.showReportedHoursRightNow());
|
||||
result.setShowingMoneyCostBar(planner.showMoneyCostBarRightNow());
|
||||
result.setShowingAdvances(planner.showAdvancesRightNow());
|
||||
|
||||
mapper.register(position, result, data);
|
||||
|
|
@ -465,6 +466,20 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMoneyCostBar() {
|
||||
for (Task task : diagramGraph.getTasks()) {
|
||||
task.setShowingMoneyCostBar(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideMoneyCostBar() {
|
||||
for (Task task : diagramGraph.getTasks()) {
|
||||
task.setShowingMoneyCostBar(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reloadCharts() {
|
||||
configuration.reloadCharts();
|
||||
|
|
@ -483,6 +498,8 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
Checkbox advances = (Checkbox) parent.getFellow("print_advances");
|
||||
Checkbox reportedHours = (Checkbox) parent
|
||||
.getFellow("print_reported_hours");
|
||||
Checkbox moneyCostBar = (Checkbox) parent
|
||||
.getFellow("print_money_cost_bar");
|
||||
|
||||
parameters.put("extension", ".png");
|
||||
if (expanded.isChecked() == true) {
|
||||
|
|
@ -497,6 +514,9 @@ public class FunctionalityExposedForExtensions<T> implements IContext<T> {
|
|||
if (reportedHours.isChecked() == true) {
|
||||
parameters.put("reportedHours", "all");
|
||||
}
|
||||
if (moneyCostBar.isChecked() == true) {
|
||||
parameters.put("moneyCostBar", "all");
|
||||
}
|
||||
if (resources.isChecked() == true) {
|
||||
parameters.put("resources", "all");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -120,6 +120,15 @@ public class Planner extends HtmlMacroComponent {
|
|||
return toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
public static boolean guessShowMoneyCostBarByDefault(
|
||||
Map<String, String[]> queryURLParameters) {
|
||||
String[] values = queryURLParameters.get("moneyCostBar");
|
||||
if (values == null) {
|
||||
return false;
|
||||
}
|
||||
return toLowercaseSet(values).contains("all");
|
||||
}
|
||||
|
||||
private static Set<String> toLowercaseSet(String[] values) {
|
||||
Set<String> result = new HashSet<String>();
|
||||
for (String each : values) {
|
||||
|
|
@ -156,6 +165,8 @@ public class Planner extends HtmlMacroComponent {
|
|||
|
||||
private boolean isShowingReportedHours = false;
|
||||
|
||||
private boolean isShowingMoneyCostBar = false;
|
||||
|
||||
private boolean isShowingResources = false;
|
||||
|
||||
private boolean isExpandAll = false;
|
||||
|
|
@ -372,6 +383,11 @@ public class Planner extends HtmlMacroComponent {
|
|||
Button showAllResources = (Button) getFellow("showAllResources");
|
||||
showAllResources.setVisible(false);
|
||||
}
|
||||
if (!configuration.isMoneyCostBarEnabled()) {
|
||||
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
|
||||
showMoneyCostBarButton.setVisible(false);
|
||||
}
|
||||
|
||||
listZoomLevels.setSelectedIndex(getZoomLevel().ordinal());
|
||||
|
||||
this.visibleChart = configuration.isExpandPlanningViewCharts();
|
||||
|
|
@ -571,12 +587,22 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
};
|
||||
|
||||
private IGraphChangeListener showMoneyCostBarOnChange = new IGraphChangeListener() {
|
||||
|
||||
@Override
|
||||
public void execute() {
|
||||
context.showMoneyCostBar();
|
||||
}
|
||||
};
|
||||
|
||||
private boolean containersExpandedByDefault = false;
|
||||
|
||||
private boolean shownAdvanceByDefault = false;
|
||||
|
||||
private boolean shownReportedHoursByDefault = false;
|
||||
|
||||
private boolean shownMoneyCostBarByDefault = false;
|
||||
|
||||
private FilterAndParentExpandedPredicates predicate;
|
||||
|
||||
private boolean visibleChart;
|
||||
|
|
@ -645,6 +671,26 @@ public class Planner extends HtmlMacroComponent {
|
|||
}
|
||||
}
|
||||
|
||||
public void showMoneyCostBar() {
|
||||
Button showMoneyCostBarButton = (Button) getFellow("showMoneyCostBar");
|
||||
if (disabilityConfiguration.isMoneyCostBarEnabled()) {
|
||||
if (isShowingMoneyCostBar) {
|
||||
context.hideMoneyCostBar();
|
||||
diagramGraph
|
||||
.removePostGraphChangeListener(showMoneyCostBarOnChange);
|
||||
showMoneyCostBarButton.setSclass("planner-command");
|
||||
showMoneyCostBarButton.setTooltiptext(_("Show money cost bar"));
|
||||
} else {
|
||||
context.showMoneyCostBar();
|
||||
diagramGraph
|
||||
.addPostGraphChangeListener(showMoneyCostBarOnChange);
|
||||
showMoneyCostBarButton.setSclass("planner-command clicked");
|
||||
showMoneyCostBarButton.setTooltiptext(_("Hide money cost bar"));
|
||||
}
|
||||
isShowingMoneyCostBar = !isShowingMoneyCostBar;
|
||||
}
|
||||
}
|
||||
|
||||
public void showAllLabels() {
|
||||
Button showAllLabelsButton = (Button) getFellow("showAllLabels");
|
||||
if (isShowingLabels) {
|
||||
|
|
@ -732,6 +778,19 @@ public class Planner extends HtmlMacroComponent {
|
|||
return (areShownReportedHoursByDefault() || isShowingReportedHours);
|
||||
}
|
||||
|
||||
public void setAreShownMoneyCostBarByDefault(
|
||||
boolean shownMoneyCostBarByDefault) {
|
||||
this.shownMoneyCostBarByDefault = shownMoneyCostBarByDefault;
|
||||
}
|
||||
|
||||
public boolean areShownMoneyCostBarByDefault() {
|
||||
return shownMoneyCostBarByDefault;
|
||||
}
|
||||
|
||||
public boolean showMoneyCostBarRightNow() {
|
||||
return (areShownMoneyCostBarByDefault() || isShowingMoneyCostBar);
|
||||
}
|
||||
|
||||
public void expandAll() {
|
||||
Button expandAllButton = (Button) getFellow("expandAll");
|
||||
if (disabilityConfiguration.isExpandAllEnabled()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -60,6 +60,7 @@ import org.zkoss.zul.Div;
|
|||
* Graphical component which represents a {@link Task}.
|
||||
*
|
||||
* @author Javier Morán Rúa <jmoran@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class TaskComponent extends Div implements AfterCompose {
|
||||
|
||||
|
|
@ -78,6 +79,8 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
|
||||
private PropertyChangeListener showingReportedHoursPropertyListener;
|
||||
|
||||
private PropertyChangeListener showingMoneyCostBarPropertyListener;
|
||||
|
||||
public static TaskComponent asTaskComponent(Task task,
|
||||
IDisabilityConfiguration disabilityConfiguration,
|
||||
boolean isTopLevel) {
|
||||
|
|
@ -278,6 +281,20 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
this.task
|
||||
.addReportedHoursPropertyChangeListener(showingReportedHoursPropertyListener);
|
||||
|
||||
if (showingMoneyCostBarPropertyListener == null) {
|
||||
showingMoneyCostBarPropertyListener = new PropertyChangeListener() {
|
||||
|
||||
@Override
|
||||
public void propertyChange(PropertyChangeEvent evt) {
|
||||
if (isInPage() && !(task instanceof Milestone)) {
|
||||
updateCompletionMoneyCostBar();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
this.task
|
||||
.addMoneyCostBarPropertyChangeListener(showingMoneyCostBarPropertyListener);
|
||||
|
||||
if (criticalPathPropertyListener == null) {
|
||||
criticalPathPropertyListener = new PropertyChangeListener() {
|
||||
|
||||
|
|
@ -491,6 +508,7 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
return;
|
||||
}
|
||||
updateCompletionReportedHours();
|
||||
updateCompletionMoneyCostBar();
|
||||
updateCompletionAdvance();
|
||||
}
|
||||
|
||||
|
|
@ -507,6 +525,19 @@ public class TaskComponent extends Div implements AfterCompose {
|
|||
}
|
||||
}
|
||||
|
||||
public void updateCompletionMoneyCostBar() {
|
||||
if (task.isShowingMoneyCostBar()) {
|
||||
int startPixels = this.task.getBeginDate().toPixels(getMapper());
|
||||
String widthMoneyCostBar = pixelsFromStartUntil(startPixels,
|
||||
this.task.getMoneyCostBarEndDate()) + "px";
|
||||
response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar",
|
||||
widthMoneyCostBar));
|
||||
} else {
|
||||
response(null, new AuInvoke(this, "resizeCompletionMoneyCostBar",
|
||||
"0px"));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateCompletionAdvance() {
|
||||
if (task.isShowingAdvances()) {
|
||||
int startPixels = this.task.getBeginDate().toPixels(getMapper());
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -22,7 +22,7 @@ package org.zkoss.ganttz.adapters;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IDisabilityConfiguration {
|
||||
|
||||
|
|
@ -40,6 +40,8 @@ public interface IDisabilityConfiguration {
|
|||
|
||||
public boolean isReportedHoursEnabled();
|
||||
|
||||
public boolean isMoneyCostBarEnabled();
|
||||
|
||||
public boolean isExpandAllEnabled();
|
||||
|
||||
public boolean isFlattenTreeEnabled();
|
||||
|
|
|
|||
|
|
@ -148,6 +148,8 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
|
||||
private boolean reportedHoursEnabled = true;
|
||||
|
||||
private boolean moneyCostBarEnabled = true;
|
||||
|
||||
private boolean expandAllEnabled = true;
|
||||
|
||||
private boolean flattenTreeEnabled = true;
|
||||
|
|
@ -345,6 +347,15 @@ public class PlannerConfiguration<T> implements IDisabilityConfiguration {
|
|||
return reportedHoursEnabled;
|
||||
}
|
||||
|
||||
public void setMoneyCostBarEnabled(boolean moneyCostBarEnabled) {
|
||||
this.moneyCostBarEnabled = moneyCostBarEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMoneyCostBarEnabled() {
|
||||
return moneyCostBarEnabled;
|
||||
}
|
||||
|
||||
public void setExpandAllEnabled(boolean expandAllEnabled) {
|
||||
this.expandAllEnabled = expandAllEnabled;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -34,6 +34,7 @@ import org.zkoss.ganttz.data.constraint.Constraint;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class DefaultFundamentalProperties implements ITaskFundamentalProperties {
|
||||
|
||||
|
|
@ -47,10 +48,14 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
|
|||
|
||||
private long hoursAdvanceEndDate;
|
||||
|
||||
private long moneyCostBarEndDate;
|
||||
|
||||
private Date advanceEndDate;
|
||||
|
||||
private BigDecimal hoursAdvancePercentage;
|
||||
|
||||
private BigDecimal moneyCostBarPercentage;
|
||||
|
||||
private BigDecimal advancePercentage;
|
||||
|
||||
private String tooltipText;
|
||||
|
|
@ -92,15 +97,19 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
|
|||
public DefaultFundamentalProperties(String name, Date beginDate,
|
||||
long lengthMilliseconds, String notes,
|
||||
Date hoursAdvanceEndDate,
|
||||
Date moneyCostBarEndDate,
|
||||
Date advanceEndDate,
|
||||
BigDecimal hoursAdvancePercentage, BigDecimal advancePercentage) {
|
||||
BigDecimal hoursAdvancePercentage,
|
||||
BigDecimal moneyCostBarPercentage, BigDecimal advancePercentage) {
|
||||
this.name = name;
|
||||
this.beginDate = beginDate.getTime();
|
||||
this.lengthMilliseconds = lengthMilliseconds;
|
||||
this.notes = notes;
|
||||
this.hoursAdvanceEndDate = hoursAdvanceEndDate.getTime();
|
||||
this.moneyCostBarEndDate = moneyCostBarEndDate.getTime();
|
||||
this.advanceEndDate = advanceEndDate;
|
||||
this.hoursAdvancePercentage = hoursAdvancePercentage;
|
||||
this.moneyCostBarPercentage = moneyCostBarPercentage;
|
||||
this.advancePercentage = advancePercentage;
|
||||
this.tooltipText = "Default tooltip";
|
||||
this.labelsText = "";
|
||||
|
|
@ -169,6 +178,11 @@ public class DefaultFundamentalProperties implements ITaskFundamentalProperties
|
|||
return GanttDate.createFrom(new Date(hoursAdvanceEndDate));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getMoneyCostBarEndDate() {
|
||||
return GanttDate.createFrom(new Date(moneyCostBarEndDate));
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getAdvanceEndDate() {
|
||||
return advanceEndDate != null ? GanttDate.createFrom(new Date(
|
||||
|
|
|
|||
|
|
@ -2427,4 +2427,4 @@ public class GanttDiagramGraph<V, D extends IDependency<V>> implements
|
|||
return adapter.getChildren(task);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -29,6 +29,7 @@ import org.zkoss.ganttz.data.constraint.Constraint;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface ITaskFundamentalProperties {
|
||||
|
||||
|
|
@ -76,6 +77,8 @@ public interface ITaskFundamentalProperties {
|
|||
|
||||
public GanttDate getHoursAdvanceEndDate();
|
||||
|
||||
public GanttDate getMoneyCostBarEndDate();
|
||||
|
||||
public GanttDate getAdvanceEndDate();
|
||||
|
||||
public BigDecimal getHoursAdvancePercentage();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -47,7 +47,9 @@ import org.zkoss.ganttz.util.WeakReferencedListeners.Mode;
|
|||
/**
|
||||
* This class contains the information of a task. It can be modified and
|
||||
* notifies of the changes to the interested parties. <br/>
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public abstract class Task implements ITaskFundamentalProperties {
|
||||
|
||||
|
|
@ -72,6 +74,9 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
private PropertyChangeSupport reportedHoursProperty = new PropertyChangeSupport(
|
||||
this);
|
||||
|
||||
private PropertyChangeSupport moneyCostBarProperty = new PropertyChangeSupport(
|
||||
this);
|
||||
|
||||
private final ITaskFundamentalProperties fundamentalProperties;
|
||||
|
||||
private boolean visible = true;
|
||||
|
|
@ -82,6 +87,8 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
|
||||
private boolean showingReportedHours = false;
|
||||
|
||||
private boolean showingMoneyCostBar = false;
|
||||
|
||||
private ConstraintViolationNotificator<GanttDate> violationNotificator = ConstraintViolationNotificator
|
||||
.create();
|
||||
|
||||
|
|
@ -241,6 +248,17 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
return showingReportedHours;
|
||||
}
|
||||
|
||||
public void setShowingMoneyCostBar(boolean showingMoneyCostBar) {
|
||||
boolean previousValue = this.showingMoneyCostBar;
|
||||
this.showingMoneyCostBar = showingMoneyCostBar;
|
||||
moneyCostBarProperty.firePropertyChange("showingMoneyCostBar",
|
||||
previousValue, this.showingMoneyCostBar);
|
||||
}
|
||||
|
||||
public boolean isShowingMoneyCostBar() {
|
||||
return showingMoneyCostBar;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return fundamentalProperties.getName();
|
||||
}
|
||||
|
|
@ -297,6 +315,11 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
this.reportedHoursProperty.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void addMoneyCostBarPropertyChangeListener(
|
||||
PropertyChangeListener listener) {
|
||||
this.moneyCostBarProperty.addPropertyChangeListener(listener);
|
||||
}
|
||||
|
||||
public void addFundamentalPropertiesChangeListener(
|
||||
PropertyChangeListener listener) {
|
||||
this.fundamentalPropertiesListeners.addPropertyChangeListener(listener);
|
||||
|
|
@ -374,6 +397,11 @@ public abstract class Task implements ITaskFundamentalProperties {
|
|||
return fundamentalProperties.getHoursAdvanceEndDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getMoneyCostBarEndDate() {
|
||||
return fundamentalProperties.getMoneyCostBarEndDate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getAdvanceEndDate() {
|
||||
return fundamentalProperties.getAdvanceEndDate();
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -35,7 +35,9 @@ import org.zkoss.zk.ui.Component;
|
|||
/**
|
||||
* An implementation of {@link IContext} that delegates to another context and
|
||||
* redefines its {@link IContext#getRelativeTo()}
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class ContextRelativeToOtherComponent<T> implements IContext<T> {
|
||||
|
||||
|
|
@ -147,4 +149,15 @@ public class ContextRelativeToOtherComponent<T> implements IContext<T> {
|
|||
public void showReportedHours() {
|
||||
context.showReportedHours();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideMoneyCostBar() {
|
||||
context.hideMoneyCostBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMoneyCostBar() {
|
||||
context.showMoneyCostBar();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -36,7 +36,9 @@ import org.zkoss.zk.ui.Component;
|
|||
* An implementation of {@link IContextWithPlannerTask} that wraps another
|
||||
* context and specifies the task to be returned by
|
||||
* {@link IContextWithPlannerTask#getTask()}
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class ContextWithPlannerTask<T> implements IContextWithPlannerTask<T> {
|
||||
|
||||
|
|
@ -149,4 +151,15 @@ public class ContextWithPlannerTask<T> implements IContextWithPlannerTask<T> {
|
|||
public void showReportedHours() {
|
||||
context.showReportedHours();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideMoneyCostBar() {
|
||||
context.hideMoneyCostBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showMoneyCostBar() {
|
||||
context.showMoneyCostBar();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -38,7 +38,9 @@ import org.zkoss.zk.ui.Component;
|
|||
|
||||
/**
|
||||
* A facade for operations allowed to extensions <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IContext<T> {
|
||||
|
||||
|
|
@ -143,4 +145,9 @@ public interface IContext<T> {
|
|||
void showReportedHours();
|
||||
|
||||
void hideReportedHours();
|
||||
|
||||
void showMoneyCostBar();
|
||||
|
||||
void hideMoneyCostBar();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -86,6 +86,12 @@ planner = self;
|
|||
sclass="planner-command"/>
|
||||
<separator />
|
||||
|
||||
<button id="showMoneyCostBar" onClick="planner.showMoneyCostBar();"
|
||||
image="/common/img/ico_money_cost_bar.png"
|
||||
tooltiptext="${ganttzk_i18n:_('Show/Hide money cost bar')}"
|
||||
sclass="planner-command"/>
|
||||
<separator />
|
||||
|
||||
<!-- Filtering -->
|
||||
<vbox id="orderFilter"/>
|
||||
<vbox id="orderElementFilter"/>
|
||||
|
|
@ -116,4 +122,4 @@ planner = self;
|
|||
<div id="insertionPointChart" />
|
||||
</south>
|
||||
</borderlayout>
|
||||
</zk>
|
||||
</zk>
|
||||
|
|
|
|||
|
|
@ -215,6 +215,9 @@ ganttz.TaskComponent = zk.$extends(zul.Widget, {
|
|||
moveConsolidatedline : function(width){
|
||||
jq('#consolidatedline' + this.parent.uuid).css('left', width);
|
||||
},
|
||||
resizeCompletionMoneyCostBar : function(width){
|
||||
jq('#' + this.uuid + ' .completionMoneyCostBar:first').css('width', width);
|
||||
},
|
||||
resizeCompletionAdvance : function(width){
|
||||
jq('#' + this.uuid + ' .completion:first').css('width', width);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ function(out){
|
|||
'z.autoz="true"',
|
||||
'class="milestone"',
|
||||
'>');
|
||||
out.push('<div class="completionMoneyCostBar"></div>');
|
||||
out.push('<div class="completion"></div>');
|
||||
out.push('<div class="completion2"></div>');
|
||||
out.push('<div class="milestone_end"></div>');
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ function(out){
|
|||
out.push('<div class="task-resources-inner">', this.getResourcesText(),'</div>');
|
||||
out.push('</div>');
|
||||
|
||||
out.push('<div class="completionMoneyCostBar"></div>');
|
||||
out.push('<div class="completion"></div>');
|
||||
out.push('<div class="completion2"></div>');
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ function(out){
|
|||
'</div>');
|
||||
|
||||
out.push('<div class="taskcontainer_completion">',
|
||||
'<div class="completionMoneyCostBar"></div>',
|
||||
'<div class="completion"></div>',
|
||||
'<div class="completion2"></div>',
|
||||
'</div>');
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1493,4 +1493,6 @@ public abstract class OrderElement extends IntegrationEntity implements
|
|||
return false;
|
||||
}
|
||||
|
||||
public abstract BigDecimal getBudget();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.AssertTrue;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.hibernate.validator.Valid;
|
||||
|
|
@ -72,6 +73,8 @@ public class OrderLine extends OrderElement {
|
|||
return result;
|
||||
}
|
||||
|
||||
private BigDecimal budget = BigDecimal.ZERO.setScale(2);
|
||||
|
||||
/**
|
||||
* Constructor for hibernate. Do not use!
|
||||
*/
|
||||
|
|
@ -370,4 +373,16 @@ public class OrderLine extends OrderElement {
|
|||
}
|
||||
}
|
||||
|
||||
public void setBudget(BigDecimal budget) {
|
||||
Validate.isTrue(budget.compareTo(BigDecimal.ZERO) >= 0,
|
||||
"budget cannot be negative");
|
||||
this.budget = budget.setScale(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull(message = "budget not specified")
|
||||
public BigDecimal getBudget() {
|
||||
return budget;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1134,4 +1134,13 @@ public class OrderLineGroup extends OrderElement implements
|
|||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudget() {
|
||||
BigDecimal budget = BigDecimal.ZERO.setScale(2);
|
||||
for (OrderElement child : children) {
|
||||
budget = budget.add(child.getBudget());
|
||||
}
|
||||
return budget;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* 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 OrderElement} taking into account all
|
||||
* its children.<br />
|
||||
*
|
||||
* It uses the {@link OrderElement} 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><br />
|
||||
*
|
||||
* If there is not relationship between resource and type of hour through
|
||||
* the cost categories, the price used is the default one for the type of
|
||||
* hour.
|
||||
*
|
||||
* @param The
|
||||
* {@link OrderElement} to calculate the money cost
|
||||
* @return Money cost of the order element and all its children
|
||||
*/
|
||||
BigDecimal getMoneyCost(OrderElement orderElement);
|
||||
|
||||
/**
|
||||
* Resets the map used to save cached values of money cost for each
|
||||
* {@link OrderElement}
|
||||
*/
|
||||
void resetMoneyCostMap();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,126 @@
|
|||
/*
|
||||
* 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>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
public class MoneyCostCalculator implements IMoneyCostCalculator {
|
||||
|
||||
@Autowired
|
||||
private IWorkReportLineDAO workReportLineDAO;
|
||||
|
||||
@Autowired
|
||||
private IHourCostDAO hourCostDAO;
|
||||
|
||||
private Map<OrderElement, BigDecimal> moneyCostMap = new HashMap<OrderElement, BigDecimal>();
|
||||
|
||||
@Override
|
||||
public void resetMoneyCostMap() {
|
||||
moneyCostMap = new HashMap<OrderElement, BigDecimal>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getMoneyCost(OrderElement orderElement) {
|
||||
BigDecimal result = moneyCostMap.get(orderElement);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = BigDecimal.ZERO.setScale(2);
|
||||
for (OrderElement each : orderElement.getChildren()) {
|
||||
result = result.add(getMoneyCost(each));
|
||||
}
|
||||
|
||||
result = result.add(getMoneyCostFromOwnWorkReportLines(orderElement))
|
||||
.setScale(2, RoundingMode.HALF_UP);
|
||||
|
||||
moneyCostMap.put(orderElement, result);
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -734,6 +734,13 @@ public abstract class TaskElement extends BaseEntity {
|
|||
return (this.getParent() == null);
|
||||
}
|
||||
|
||||
public BigDecimal getBudget() {
|
||||
if ((taskSource != null) && (taskSource.getOrderElement() != null)) {
|
||||
return taskSource.getOrderElement().getBudget();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public ExternalCompany getSubcontractedCompany() {
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -594,4 +594,6 @@ public abstract class OrderElementTemplate extends BaseEntity implements
|
|||
this.origin = origin;
|
||||
}
|
||||
|
||||
public abstract BigDecimal getBudget();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
package org.libreplan.business.templates.entities;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -276,4 +277,13 @@ public class OrderLineGroupTemplate extends OrderElementTemplate implements
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudget() {
|
||||
BigDecimal budget = BigDecimal.ZERO.setScale(2);
|
||||
for (OrderElementTemplate child : children) {
|
||||
budget = budget.add(child.getBudget());
|
||||
}
|
||||
return budget;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package org.libreplan.business.templates.entities;
|
|||
|
||||
import static org.libreplan.business.i18n.I18nHelper._;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
|
@ -29,6 +30,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.lang.Validate;
|
||||
import org.hibernate.validator.NotNull;
|
||||
import org.hibernate.validator.Valid;
|
||||
import org.libreplan.business.orders.entities.HoursGroup;
|
||||
|
|
@ -51,6 +53,7 @@ public class OrderLineTemplate extends OrderElementTemplate {
|
|||
public static OrderLineTemplate create(OrderLine orderLine) {
|
||||
OrderLineTemplate beingBuilt = new OrderLineTemplate();
|
||||
copyHoursGroup(orderLine.getHoursGroups(), beingBuilt);
|
||||
beingBuilt.setBudget(orderLine.getBudget());
|
||||
return create(beingBuilt, orderLine);
|
||||
}
|
||||
|
||||
|
|
@ -67,9 +70,12 @@ public class OrderLineTemplate extends OrderElementTemplate {
|
|||
return createNew(new OrderLineTemplate());
|
||||
}
|
||||
|
||||
private BigDecimal budget = BigDecimal.ZERO.setScale(2);
|
||||
|
||||
protected <T extends OrderElement> T setupElementParts(T orderElement) {
|
||||
super.setupElementParts(orderElement);
|
||||
setupHoursGroups((OrderLine) orderElement);
|
||||
setupBudget((OrderLine) orderElement);
|
||||
return orderElement;
|
||||
}
|
||||
|
||||
|
|
@ -81,6 +87,10 @@ public class OrderLineTemplate extends OrderElementTemplate {
|
|||
orderLine.setHoursGroups(result);
|
||||
}
|
||||
|
||||
private void setupBudget(OrderLine orderLine) {
|
||||
orderLine.setBudget(getBudget());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OrderElementTemplate> getChildrenTemplates() {
|
||||
return Collections.emptyList();
|
||||
|
|
@ -215,4 +225,16 @@ public class OrderLineTemplate extends OrderElementTemplate {
|
|||
hoursGroupOrderLineTemplateHandler.recalculateHoursGroups(this);
|
||||
}
|
||||
|
||||
public void setBudget(BigDecimal budget) {
|
||||
Validate.isTrue(budget.compareTo(BigDecimal.ZERO) >= 0,
|
||||
"budget cannot be negative");
|
||||
this.budget = budget.setScale(2);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull(message = "budget not specified")
|
||||
public BigDecimal getBudget() {
|
||||
return budget;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -70,7 +70,9 @@ import org.libreplan.business.calendars.entities.Capacity;
|
|||
* @see PartialDay
|
||||
* @see LocalDate
|
||||
* @see EffortDuration
|
||||
*
|
||||
* @author Óscar González Fernández
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*
|
||||
*/
|
||||
public class IntraDayDate implements Comparable<IntraDayDate> {
|
||||
|
|
@ -497,4 +499,57 @@ public class IntraDayDate implements Comparable<IntraDayDate> {
|
|||
return startOfDay(date);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link EffortDuration} until {@code end} considering 8h per
|
||||
* day of effort.
|
||||
*
|
||||
* @param end
|
||||
* @return The {@link EffortDuration} until {@code end}
|
||||
*/
|
||||
public EffortDuration effortUntil(IntraDayDate end) {
|
||||
Validate.isTrue(compareTo(end) <= 0);
|
||||
int days = Days.daysBetween(getDate(), end.getDate()).getDays();
|
||||
|
||||
EffortDuration result = EffortDuration.hours(days * 8);
|
||||
|
||||
if (!getEffortDuration().isZero()) {
|
||||
result = result.minus(EffortDuration.hours(8));
|
||||
result = result.plus(EffortDuration.hours(8).minus(
|
||||
getEffortDuration()));
|
||||
}
|
||||
|
||||
if (!end.getEffortDuration().isZero()) {
|
||||
result = result.plus(end.getEffortDuration());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link IntraDayDate} adding the {@code effort} considering 8h
|
||||
* per day of effort.
|
||||
*
|
||||
* @param effort
|
||||
* @return The {@link IntraDayDate} result of adding the {@code effort}
|
||||
*/
|
||||
public IntraDayDate addEffort(EffortDuration effort) {
|
||||
int secondsPerDay = 3600 * 8;
|
||||
|
||||
int seconds = effort.getSeconds();
|
||||
|
||||
if (!getEffortDuration().isZero()) {
|
||||
seconds += getEffortDuration().getSeconds();
|
||||
}
|
||||
|
||||
int days = seconds / secondsPerDay;
|
||||
|
||||
EffortDuration extraEffort = EffortDuration.zero();
|
||||
int extra = seconds % secondsPerDay;
|
||||
if (extra != 0) {
|
||||
extraEffort = extraEffort.plus(EffortDuration.seconds(extra));
|
||||
}
|
||||
|
||||
return IntraDayDate.create(getDate().plusDays(days), extraEffort);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,4 +68,26 @@
|
|||
<modifyDataType tableName="order_element_template" columnName="description" newDataType="TEXT" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-budget-column-to-order_line" author="mrego">
|
||||
<comment>add budget column to order_line</comment>
|
||||
<addColumn tableName="order_line">
|
||||
<column name="budget" type="DECIMAL(19,2)" />
|
||||
</addColumn>
|
||||
<addNotNullConstraint tableName="order_line"
|
||||
columnName="budget" defaultNullValue="0" />
|
||||
<addDefaultValue tableName="order_line"
|
||||
columnName="budget" defaultValueNumeric="0" />
|
||||
</changeSet>
|
||||
|
||||
<changeSet id="add-budget-column-to-order_line_template" author="mrego">
|
||||
<comment>add budget column to order_line_template</comment>
|
||||
<addColumn tableName="order_line_template">
|
||||
<column name="budget" type="DECIMAL(19,2)" />
|
||||
</addColumn>
|
||||
<addNotNullConstraint tableName="order_line_template"
|
||||
columnName="budget" defaultNullValue="0" />
|
||||
<addDefaultValue tableName="order_line_template"
|
||||
columnName="budget" defaultValueNumeric="0" />
|
||||
</changeSet>
|
||||
|
||||
</databaseChangeLog>
|
||||
|
|
|
|||
|
|
@ -160,6 +160,8 @@
|
|||
|
||||
<property name="lastHoursGroupSequenceCode"
|
||||
column="last_hours_group_sequence_code" access="field" />
|
||||
|
||||
<property name="budget" scale="2" access="field" />
|
||||
</joined-subclass>
|
||||
</class>
|
||||
|
||||
|
|
|
|||
|
|
@ -87,6 +87,8 @@
|
|||
|
||||
<property name="lastHoursGroupSequenceCode" access="field"
|
||||
column="last_hours_group_sequence_code" />
|
||||
|
||||
<property name="budget" scale="2" access="field" />
|
||||
</joined-subclass>
|
||||
</class>
|
||||
|
||||
|
|
|
|||
|
|
@ -1175,4 +1175,25 @@ public class OrderElementTest {
|
|||
.getAdvanceType(), equalTo(advanceType2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkPositiveBudgetInOrderLine() {
|
||||
OrderLine line = givenOrderLine("task", "code", 10);
|
||||
line.setBudget(new BigDecimal(100));
|
||||
assertThat(line.getBudget(), equalTo(new BigDecimal(100).setScale(2)));
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void checkNonNegativeBudgetInOrderLine() {
|
||||
OrderLine line = givenOrderLine("task", "code", 10);
|
||||
line.setBudget(new BigDecimal(-100));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkBudgetInOrderLineGroup() {
|
||||
OrderLineGroup group = givenOrderLineGroupWithTwoOrderLines(20, 30);
|
||||
((OrderLine) group.getChildren().get(0)).setBudget(new BigDecimal(50));
|
||||
((OrderLine) group.getChildren().get(1)).setBudget(new BigDecimal(70));
|
||||
assertThat(group.getBudget(), equalTo(new BigDecimal(120).setScale(2)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,386 @@
|
|||
/*
|
||||
* 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.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.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.libreplan.business.IDataBootstrap;
|
||||
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.orders.entities.OrderLineGroup;
|
||||
import org.libreplan.business.planner.entities.IMoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.MoneyCostCalculator;
|
||||
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.scenarios.IScenarioManager;
|
||||
import org.libreplan.business.scenarios.daos.IOrderVersionDAO;
|
||||
import org.libreplan.business.scenarios.entities.OrderVersion;
|
||||
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 {
|
||||
|
||||
@javax.annotation.Resource
|
||||
private IDataBootstrap scenariosBootstrap;
|
||||
|
||||
@Before
|
||||
public void loadRequiredaData() {
|
||||
scenariosBootstrap.loadRequiredData();
|
||||
}
|
||||
|
||||
@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;
|
||||
|
||||
@Autowired
|
||||
private IOrderVersionDAO orderVersionDAO;
|
||||
|
||||
@Autowired
|
||||
private IScenarioManager scenarioManager;
|
||||
|
||||
private List<TypeOfWorkHours> typesOfWorkHours = new ArrayList<TypeOfWorkHours>();
|
||||
private CostCategory costCategory;
|
||||
private Resource resource;
|
||||
private List<OrderElement> orderElements = new ArrayList<OrderElement>();
|
||||
private WorkReportType workReportType;
|
||||
private WorkReport workReport;
|
||||
|
||||
private void givenTypeOfWorkHours(BigDecimal defaultPrice) {
|
||||
TypeOfWorkHours typeOfWorkHours = TypeOfWorkHours.createUnvalidated(
|
||||
"default-type-of-work-hours-" + UUID.randomUUID(),
|
||||
"default-type-of-work-hours-" + UUID.randomUUID(), true,
|
||||
defaultPrice);
|
||||
typeOfWorkHoursDAO.save(typeOfWorkHours);
|
||||
typesOfWorkHours.add(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(typesOfWorkHours.get(0));
|
||||
costCategory.addHourCost(hourCost);
|
||||
costCategoryDAO.save(costCategory);
|
||||
}
|
||||
|
||||
private void givenResource(boolean relatedWithCostCategory) {
|
||||
resource = Worker.createUnvalidated("default-resource",
|
||||
"default-resource", "default-resource", "default-resource");
|
||||
|
||||
if (relatedWithCostCategory) {
|
||||
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 orderElement = OrderLine.createOrderLineWithUnfixedPercentage(100);
|
||||
orderElement.setCode("default-order-element-" + UUID.randomUUID());
|
||||
orderElement.setName("default-order-element-" + UUID.randomUUID());
|
||||
orderElement.getHoursGroups().get(0)
|
||||
.setCode("default-hours-group-" + UUID.randomUUID());
|
||||
orderElementDAO.save(orderElement);
|
||||
|
||||
orderElements.add(orderElement);
|
||||
}
|
||||
|
||||
private void givenOrderLineGroupWithTwoLines() {
|
||||
OrderLineGroup orderLineGroup = OrderLineGroup.create();
|
||||
orderLineGroup.setCode("default-order-line-group-" + UUID.randomUUID());
|
||||
orderLineGroup.setName("default-order-line-group-" + UUID.randomUUID());
|
||||
|
||||
OrderVersion orderVersion = OrderVersion
|
||||
.createInitialVersion(scenarioManager.getCurrent());
|
||||
orderVersionDAO.save(orderVersion);
|
||||
orderLineGroup.useSchedulingDataFor(orderVersion);
|
||||
|
||||
OrderLine orderLine1 = OrderLine
|
||||
.createOrderLineWithUnfixedPercentage(100);
|
||||
orderLine1.setCode("order-line-1-" + UUID.randomUUID());
|
||||
orderLine1.setName("order-line-1-" + UUID.randomUUID());
|
||||
orderLine1.getHoursGroups().get(0)
|
||||
.setCode("hours-group-1-" + UUID.randomUUID());
|
||||
orderLineGroup.add(orderLine1);
|
||||
|
||||
OrderLine orderLine2 = OrderLine
|
||||
.createOrderLineWithUnfixedPercentage(100);
|
||||
orderLine2.setCode("order-line-2-" + UUID.randomUUID());
|
||||
orderLine2.setName("order-line-2-" + UUID.randomUUID());
|
||||
orderLine2.getHoursGroups().get(0)
|
||||
.setCode("hours-group-2-" + UUID.randomUUID());
|
||||
orderLineGroup.add(orderLine2);
|
||||
|
||||
orderElementDAO.save(orderLineGroup);
|
||||
|
||||
orderElements.add(orderLineGroup);
|
||||
orderElements.add(orderLine1);
|
||||
orderElements.add(orderLine2);
|
||||
}
|
||||
|
||||
private void giveWorkReportType() {
|
||||
workReportType = WorkReportType.create("default-work-report-type",
|
||||
"default-work-report-type");
|
||||
workReportTypeDAO.save(workReportType);
|
||||
}
|
||||
|
||||
private void givenWorkReport() {
|
||||
givenWorkReport(null);
|
||||
}
|
||||
|
||||
private void givenWorkReport(List<Integer> hoursList) {
|
||||
workReport = WorkReport.create(workReportType);
|
||||
workReport.setCode("default-work-report");
|
||||
|
||||
for (OrderElement each : orderElements) {
|
||||
int hours = 10;
|
||||
if (hoursList != null) {
|
||||
hours = hoursList.get(orderElements.indexOf(each));
|
||||
}
|
||||
workReport.addWorkReportLine(createWorkReportLine(each, hours));
|
||||
}
|
||||
|
||||
workReportDAO.save(workReport);
|
||||
}
|
||||
|
||||
private void givenWorkReportWithSeveralLines(List<Integer> hoursList,
|
||||
List<TypeOfWorkHours> types) {
|
||||
workReport = WorkReport.create(workReportType);
|
||||
workReport.setCode("default-work-report");
|
||||
|
||||
for (Integer hour : hoursList) {
|
||||
workReport.addWorkReportLine(createWorkReportLine(hour,
|
||||
types.get(hoursList.indexOf(hour))));
|
||||
}
|
||||
|
||||
workReportDAO.save(workReport);
|
||||
}
|
||||
|
||||
private WorkReportLine createWorkReportLine(OrderElement orderElement,
|
||||
Integer hours) {
|
||||
WorkReportLine workReportLine = WorkReportLine.create(workReport);
|
||||
workReportLine.setCode("default-work-report-line-" + UUID.randomUUID());
|
||||
workReportLine.setDate(new Date());
|
||||
workReportLine.setResource(resource);
|
||||
workReportLine.setOrderElement(orderElement);
|
||||
workReportLine.setTypeOfWorkHours(typesOfWorkHours.get(0));
|
||||
workReportLine.setEffort(EffortDuration.hours(hours));
|
||||
return workReportLine;
|
||||
}
|
||||
|
||||
private WorkReportLine createWorkReportLine(Integer hours,
|
||||
TypeOfWorkHours type) {
|
||||
WorkReportLine workReportLine = WorkReportLine.create(workReport);
|
||||
workReportLine.setCode("default-work-report-line-" + UUID.randomUUID());
|
||||
workReportLine.setDate(new Date());
|
||||
workReportLine.setResource(resource);
|
||||
workReportLine.setOrderElement(orderElements.get(0));
|
||||
workReportLine.setTypeOfWorkHours(type);
|
||||
workReportLine.setEffort(EffortDuration.hours(hours));
|
||||
return workReportLine;
|
||||
}
|
||||
|
||||
private void givenBasicExample() {
|
||||
givenTypeOfWorkHours(new BigDecimal(30));
|
||||
givenCostCategory();
|
||||
givenResource(true);
|
||||
givenOrderElement();
|
||||
giveWorkReportType();
|
||||
givenWorkReport();
|
||||
}
|
||||
|
||||
private void givenBasicExampleWithoutCostCategoryRelationship() {
|
||||
givenTypeOfWorkHours(new BigDecimal(30));
|
||||
givenResource(false);
|
||||
givenOrderElement();
|
||||
giveWorkReportType();
|
||||
givenWorkReport();
|
||||
}
|
||||
|
||||
private void givenExampleOrderLineGroup() {
|
||||
givenTypeOfWorkHours(new BigDecimal(30));
|
||||
givenCostCategory();
|
||||
givenResource(true);
|
||||
givenOrderLineGroupWithTwoLines();
|
||||
giveWorkReportType();
|
||||
givenWorkReport();
|
||||
}
|
||||
|
||||
private void givenExampleOrderLineGroupWithDifferentHours(
|
||||
List<Integer> hoursList) {
|
||||
givenTypeOfWorkHours(new BigDecimal(30));
|
||||
givenCostCategory();
|
||||
givenResource(true);
|
||||
givenOrderLineGroupWithTwoLines();
|
||||
giveWorkReportType();
|
||||
givenWorkReport(hoursList);
|
||||
}
|
||||
|
||||
private void givenExampleWithoutCostCategoryRelationshipButDifferentTypeOfHours(
|
||||
List<Integer> hoursList, List<BigDecimal> pricesList) {
|
||||
for (BigDecimal price : pricesList) {
|
||||
givenTypeOfWorkHours(price);
|
||||
}
|
||||
givenResource(false);
|
||||
givenOrderElement();
|
||||
giveWorkReportType();
|
||||
|
||||
givenWorkReportWithSeveralLines(hoursList, typesOfWorkHours);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicTest() {
|
||||
givenBasicExample();
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void basicTestWithoutCostCategoryRelationship() {
|
||||
givenBasicExampleWithoutCostCategoryRelationship();
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(300).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleOrderLineGroup() {
|
||||
givenExampleOrderLineGroup();
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(1500).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(1)),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(2)),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleOrderLineGroupWithDifferentHours1() {
|
||||
givenExampleOrderLineGroupWithDifferentHours(Arrays.asList(0, 10, 5));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(750).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(1)),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(2)),
|
||||
equalTo(new BigDecimal(250).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleOrderLineGroupWithDifferentHours2() {
|
||||
givenExampleOrderLineGroupWithDifferentHours(Arrays.asList(6, 0, 0));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(300).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(1)),
|
||||
equalTo(new BigDecimal(0).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(2)),
|
||||
equalTo(new BigDecimal(0).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleOrderLineGroupWithDifferentHours3() {
|
||||
givenExampleOrderLineGroupWithDifferentHours(Arrays.asList(6, 5, 10));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(1050).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(1)),
|
||||
equalTo(new BigDecimal(250).setScale(2)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(2)),
|
||||
equalTo(new BigDecimal(500).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleWithoutCostCategoryRelationshipButDifferentTypeOfHours1() {
|
||||
givenExampleWithoutCostCategoryRelationshipButDifferentTypeOfHours(
|
||||
Arrays.asList(10, 5),
|
||||
Arrays.asList(new BigDecimal(30), new BigDecimal(50)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(550).setScale(2)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void exampleWithoutCostCategoryRelationshipButDifferentTypeOfHours2() {
|
||||
givenExampleWithoutCostCategoryRelationshipButDifferentTypeOfHours(
|
||||
Arrays.asList(10, 5, 8), Arrays.asList(new BigDecimal(30),
|
||||
new BigDecimal(50), new BigDecimal(40)));
|
||||
assertThat(moneyCostCalculator.getMoneyCost(orderElements.get(0)),
|
||||
equalTo(new BigDecimal(870).setScale(2)));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -51,7 +51,7 @@ import org.libreplan.business.workingday.ResourcesPerDay;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández
|
||||
*
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class IntraDayDateTest {
|
||||
|
||||
|
|
@ -367,4 +367,79 @@ public class IntraDayDateTest {
|
|||
.getDate(), equalTo(today));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateEffortBetweenTwoDates() {
|
||||
IntraDayDate start = IntraDayDate.create(today, zero());
|
||||
IntraDayDate end = IntraDayDate.create(today.plusDays(3), hours(0));
|
||||
|
||||
assertThat(start.effortUntil(end), equalTo(hours(8 * 3)));
|
||||
|
||||
end = IntraDayDate.create(today.plusDays(3), hours(8));
|
||||
assertThat(start.effortUntil(end), equalTo(hours(8 * 4)));
|
||||
|
||||
start = IntraDayDate.create(today, hours(8));
|
||||
end = IntraDayDate.create(today.plusDays(3), hours(0));
|
||||
assertThat(start.effortUntil(end), equalTo(hours(8 * 2)));
|
||||
|
||||
start = IntraDayDate.create(today, hours(3));
|
||||
assertThat(start.effortUntil(end), equalTo(hours(8 * 2 + 5)));
|
||||
|
||||
end = IntraDayDate.create(today.plusDays(3), hours(6));
|
||||
assertThat(start.effortUntil(end), equalTo(hours(8 * 2 + 5 + 6)));
|
||||
|
||||
end = IntraDayDate.create(today.plusDays(3), minutes(30));
|
||||
assertThat(start.effortUntil(end),
|
||||
equalTo(hours(8 * 2 + 5).plus(minutes(30))));
|
||||
|
||||
start = IntraDayDate.create(today, hours(5).plus(minutes(40)));
|
||||
assertThat(start.effortUntil(end),
|
||||
equalTo(hours(8 * 2 + 2).plus(minutes(50))));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void calculateAddEffort() {
|
||||
IntraDayDate start = IntraDayDate.create(today, zero());
|
||||
|
||||
assertThat(start.addEffort(hours(24)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(3), hours(0))));
|
||||
|
||||
assertThat(start.addEffort(hours(20)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2), hours(4))));
|
||||
|
||||
assertThat(
|
||||
start.addEffort(hours(20).plus(minutes(20))),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2),
|
||||
hours(4).plus(minutes(20)))));
|
||||
|
||||
start = IntraDayDate.create(today, hours(3));
|
||||
assertThat(start.addEffort(hours(24)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(3), hours(3))));
|
||||
|
||||
assertThat(start.addEffort(hours(20)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2), hours(7))));
|
||||
|
||||
assertThat(start.addEffort(hours(20).plus(minutes(20))),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2),
|
||||
hours(7).plus(minutes(20)))));
|
||||
|
||||
start = IntraDayDate.create(today, hours(3).plus(minutes(40)));
|
||||
assertThat(
|
||||
start.addEffort(hours(24)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(3),
|
||||
hours(3).plus(minutes(40)))));
|
||||
|
||||
assertThat(
|
||||
start.addEffort(hours(20)),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2),
|
||||
hours(7).plus(minutes(40)))));
|
||||
|
||||
assertThat(start.addEffort(hours(20).plus(minutes(20))),
|
||||
equalTo(IntraDayDate.create(today.plusDays(3), hours(0))));
|
||||
|
||||
assertThat(
|
||||
start.addEffort(hours(20).plus(minutes(10))),
|
||||
equalTo(IntraDayDate.create(today.plusDays(2),
|
||||
hours(7).plus(minutes(50)))));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,6 +21,7 @@
|
|||
|
||||
package org.libreplan.web.orders;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
|
|
@ -33,7 +34,9 @@ import org.zkoss.zul.Vbox;
|
|||
|
||||
/**
|
||||
* Controller for show the asigned hours of the selected order element<br />
|
||||
*
|
||||
* @author Susana Montes Pedreria <smontes@wirelessgalicia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public class AssignedHoursToOrderElementController extends
|
||||
GenericForwardComposer {
|
||||
|
|
@ -42,6 +45,14 @@ public class AssignedHoursToOrderElementController extends
|
|||
|
||||
private Vbox orderElementHours;
|
||||
|
||||
private Progressmeter hoursProgressBar;
|
||||
|
||||
private Progressmeter exceedHoursProgressBar;
|
||||
|
||||
private Progressmeter moneyCostProgressBar;
|
||||
|
||||
private Progressmeter exceedMoneyCostProgressBar;
|
||||
|
||||
@Override
|
||||
public void doAfterCompose(Component comp) throws Exception {
|
||||
super.doAfterCompose(comp);
|
||||
|
|
@ -76,6 +87,18 @@ public class AssignedHoursToOrderElementController extends
|
|||
return assignedHoursToOrderElementModel.getProgressWork();
|
||||
}
|
||||
|
||||
public BigDecimal getBudget() {
|
||||
return assignedHoursToOrderElementModel.getBudget();
|
||||
}
|
||||
|
||||
public BigDecimal getMoneyCost() {
|
||||
return assignedHoursToOrderElementModel.getMoneyCost();
|
||||
}
|
||||
|
||||
public BigDecimal getMoneyCostPercentage() {
|
||||
return assignedHoursToOrderElementModel.getMoneyCostPercentage();
|
||||
}
|
||||
|
||||
private IOrderElementModel orderElementModel;
|
||||
|
||||
public void openWindow(IOrderElementModel orderElementModel) {
|
||||
|
|
@ -87,7 +110,12 @@ public class AssignedHoursToOrderElementController extends
|
|||
Util.reloadBindings(orderElementHours);
|
||||
}
|
||||
|
||||
paintProgressBars();
|
||||
}
|
||||
|
||||
public void paintProgressBars() {
|
||||
viewPercentage();
|
||||
showMoneyCostPercentageBars();
|
||||
}
|
||||
|
||||
public void setOrderElementModel(IOrderElementModel orderElementModel) {
|
||||
|
|
@ -98,10 +126,6 @@ public class AssignedHoursToOrderElementController extends
|
|||
return orderElementModel.getOrderElement();
|
||||
}
|
||||
|
||||
private Progressmeter hoursProgressBar;
|
||||
|
||||
private Progressmeter exceedHoursProgressBar;
|
||||
|
||||
/**
|
||||
* This method shows the percentage of the imputed hours with respect to the
|
||||
* estimated hours.If the hours imputed is greater that the hours estimated
|
||||
|
|
@ -110,17 +134,29 @@ public class AssignedHoursToOrderElementController extends
|
|||
private void viewPercentage() {
|
||||
if (this.getProgressWork() > 100) {
|
||||
hoursProgressBar.setValue(100);
|
||||
|
||||
exceedHoursProgressBar.setVisible(true);
|
||||
exceedHoursProgressBar.setValue(0);
|
||||
String exceedValue = String.valueOf(getProgressWork() - 100);
|
||||
exceedHoursProgressBar.setWidth(exceedValue + "px");
|
||||
exceedHoursProgressBar.setLeft("left");
|
||||
exceedHoursProgressBar
|
||||
.setStyle("background:red ; border:1px solid red");
|
||||
} else {
|
||||
hoursProgressBar.setValue(getProgressWork());
|
||||
exceedHoursProgressBar.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void showMoneyCostPercentageBars() {
|
||||
BigDecimal moneyCostPercentage = getMoneyCostPercentage();
|
||||
if (moneyCostPercentage.compareTo(new BigDecimal(100)) > 0) {
|
||||
moneyCostProgressBar.setValue(100);
|
||||
|
||||
exceedMoneyCostProgressBar.setVisible(true);
|
||||
exceedMoneyCostProgressBar.setWidth(moneyCostPercentage.subtract(
|
||||
new BigDecimal(100)).intValue()
|
||||
+ "px");
|
||||
} else {
|
||||
moneyCostProgressBar.setValue(moneyCostPercentage.intValue());
|
||||
exceedMoneyCostProgressBar.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -32,6 +32,7 @@ import org.apache.commons.lang.Validate;
|
|||
import org.joda.time.LocalDate;
|
||||
import org.libreplan.business.orders.daos.IOrderElementDAO;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.planner.entities.MoneyCostCalculator;
|
||||
import org.libreplan.business.reports.dtos.WorkReportLineDTO;
|
||||
import org.libreplan.business.workingday.EffortDuration;
|
||||
import org.libreplan.business.workreports.daos.IWorkReportLineDAO;
|
||||
|
|
@ -46,6 +47,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
*
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
* @author Ignacio Díaz Teijido <ignacio.diaz@comtecsf.es>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -58,6 +60,9 @@ public class AssignedHoursToOrderElementModel implements
|
|||
@Autowired
|
||||
private IOrderElementDAO orderElementDAO;
|
||||
|
||||
@Autowired
|
||||
private MoneyCostCalculator moneyCostCalculator;
|
||||
|
||||
private EffortDuration assignedDirectEffort;
|
||||
|
||||
private OrderElement orderElement;
|
||||
|
|
@ -197,4 +202,32 @@ public class AssignedHoursToOrderElementModel implements
|
|||
.multiply(new BigDecimal(100)).intValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudget() {
|
||||
if (orderElement == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return orderElement.getBudget();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getMoneyCost() {
|
||||
if (orderElement == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return moneyCostCalculator.getMoneyCost(orderElement);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public BigDecimal getMoneyCostPercentage() {
|
||||
if (orderElement == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return MoneyCostCalculator.getMoneyCostProportion(
|
||||
moneyCostCalculator.getMoneyCost(orderElement),
|
||||
orderElement.getBudget()).multiply(new BigDecimal(100));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,4 +60,11 @@ public class DetailsOrderElementController extends
|
|||
return orderElementModel.isCodeAutogenerated();
|
||||
}
|
||||
|
||||
public boolean isContainer() {
|
||||
if (orderElementModel.getOrderElement() == null) {
|
||||
return false;
|
||||
}
|
||||
return !orderElementModel.getOrderElement().isLeaf();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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,6 +21,7 @@
|
|||
|
||||
package org.libreplan.web.orders;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.List;
|
||||
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
|
|
@ -29,6 +30,7 @@ import org.libreplan.business.workingday.EffortDuration;
|
|||
|
||||
/**
|
||||
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
public interface IAssignedHoursToOrderElementModel{
|
||||
public List<WorkReportLineDTO> getWorkReportLines();
|
||||
|
|
@ -42,4 +44,11 @@ public interface IAssignedHoursToOrderElementModel{
|
|||
public int getProgressWork();
|
||||
|
||||
public EffortDuration getAssignedDirectEffort();
|
||||
|
||||
BigDecimal getBudget();
|
||||
|
||||
BigDecimal getMoneyCost();
|
||||
|
||||
BigDecimal getMoneyCostPercentage();
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -491,14 +491,18 @@ public class OrderCRUDController extends GenericForwardComposer {
|
|||
}
|
||||
setCurrentTab();
|
||||
|
||||
Component orderElementHours = editWindow
|
||||
.getFellowIfAny("orderElementHours");
|
||||
if (assignedHoursController == null) {
|
||||
Component orderElementHours = editWindow
|
||||
.getFellowIfAny("orderElementHours");
|
||||
assignedHoursController = (AssignedHoursToOrderElementController) orderElementHours
|
||||
.getVariable("assignedHoursToOrderElementController", true);
|
||||
|
||||
final IOrderElementModel orderElementModel = getOrderElementModel();
|
||||
assignedHoursController.openWindow(orderElementModel);
|
||||
} else {
|
||||
Util.createBindingsFor(orderElementHours);
|
||||
Util.reloadBindings(orderElementHours);
|
||||
assignedHoursController.paintProgressBars();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ public class OrderElementController extends GenericForwardComposer {
|
|||
assignedHoursToOrderElementController.openWindow(orderElementModel);
|
||||
} else {
|
||||
redraw(orderElementHours);
|
||||
assignedHoursToOrderElementController.paintProgressBars();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ package org.libreplan.web.orders;
|
|||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Date;
|
||||
|
|
@ -393,6 +394,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
|
|||
.getOrderElementModel(currentOrderElement);
|
||||
orderElementController.openWindow(model);
|
||||
updateHoursFor(currentOrderElement);
|
||||
updateBudgetFor(currentOrderElement);
|
||||
}
|
||||
|
||||
protected void addCodeCell(final OrderElement orderElement) {
|
||||
|
|
@ -618,6 +620,7 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
|
|||
public void refreshRow(Treeitem item) {
|
||||
try {
|
||||
getRenderer().updateHoursFor((OrderElement) item.getValue());
|
||||
getRenderer().updateBudgetFor((OrderElement) item.getValue());
|
||||
getRenderer().render(item, item.getValue());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
@ -718,4 +721,25 @@ public class OrderElementTreeController extends TreeController<OrderElement> {
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IBudgetHandler<OrderElement> getBudgetHandler() {
|
||||
return new IBudgetHandler<OrderElement>() {
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudgetFor(OrderElement element) {
|
||||
return element.getBudget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBudgetHours(OrderElement element,
|
||||
BigDecimal budget) {
|
||||
if (element instanceof OrderLine) {
|
||||
OrderLine line = (OrderLine) element;
|
||||
line.setBudget(budget);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (C) 2009-2010 Fundación para o Fomento da Calidade Industrial e
|
||||
* Desenvolvemento Tecnolóxico de Galicia
|
||||
* Copyright (C) 2011 Igalia, S.L.
|
||||
* 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
|
||||
|
|
@ -55,6 +55,7 @@ import org.libreplan.business.orders.entities.HoursGroup;
|
|||
import org.libreplan.business.orders.entities.Order;
|
||||
import org.libreplan.business.orders.entities.OrderElement;
|
||||
import org.libreplan.business.orders.entities.OrderLineGroup;
|
||||
import org.libreplan.business.planner.entities.IMoneyCostCalculator;
|
||||
import org.libreplan.business.qualityforms.daos.IQualityFormDAO;
|
||||
import org.libreplan.business.qualityforms.entities.QualityForm;
|
||||
import org.libreplan.business.requirements.entities.DirectCriterionRequirement;
|
||||
|
|
@ -95,9 +96,11 @@ import org.zkoss.zk.ui.Desktop;
|
|||
|
||||
/**
|
||||
* Model for UI operations related to {@link Order}. <br />
|
||||
*
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Diego Pino García <dpino@igalia.com>
|
||||
* @author Jacobo Aragunde Pérez <jaragunde@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Service
|
||||
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
||||
|
|
@ -165,6 +168,9 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
|
|||
@Autowired
|
||||
private IOrderVersionDAO orderVersionDAO;
|
||||
|
||||
@Autowired
|
||||
private IMoneyCostCalculator moneyCostCalculator;
|
||||
|
||||
@Override
|
||||
@Transactional(readOnly = true)
|
||||
public List<Label> getLabels() {
|
||||
|
|
@ -676,8 +682,8 @@ public class OrderModel extends IntegrationEntityModel implements IOrderModel {
|
|||
orderDAO.reattachUnmodifiedEntity(order);
|
||||
StringBuilder result = new StringBuilder();
|
||||
result.append(_("Progress") + ": ").append(getEstimatedAdvance(order)).append("% , ");
|
||||
result.append(_("Hours invested") + ": ").append(
|
||||
getHoursAdvancePercentage(order)).append("% \n");
|
||||
result.append(_("Hours invested") + ": ")
|
||||
.append(getHoursAdvancePercentage(order)).append("%\n");
|
||||
|
||||
if (!getDescription(order).equals("")) {
|
||||
result.append(" , " + _("Description") + ": "
|
||||
|
|
|
|||
|
|
@ -76,6 +76,16 @@ public class OrdersTreeComponent extends TreeComponent {
|
|||
treeRenderer.addHoursCell(currentElement);
|
||||
}
|
||||
|
||||
});
|
||||
columns.add(new OrdersTreeColumn(_("Budget"), "budget",
|
||||
_("Total task budget")) {
|
||||
|
||||
@Override
|
||||
protected void doCell(OrderElementTreeitemRenderer treeRenderer,
|
||||
OrderElement currentElement) {
|
||||
treeRenderer.addBudgetCell(currentElement);
|
||||
}
|
||||
|
||||
});
|
||||
columns.add(new OrdersTreeColumn(_("Must start after"),
|
||||
"estimated_init",
|
||||
|
|
|
|||
|
|
@ -69,7 +69,9 @@ import org.libreplan.business.planner.daos.ITaskElementDAO;
|
|||
import org.libreplan.business.planner.entities.Dependency;
|
||||
import org.libreplan.business.planner.entities.Dependency.Type;
|
||||
import org.libreplan.business.planner.entities.GenericResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.IMoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.ITaskPositionConstrained;
|
||||
import org.libreplan.business.planner.entities.MoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.PositionConstraintType;
|
||||
import org.libreplan.business.planner.entities.ResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.ResourceAllocation.Direction;
|
||||
|
|
@ -108,6 +110,7 @@ import org.zkoss.ganttz.util.ReentranceGuard.IReentranceCases;
|
|||
|
||||
/**
|
||||
* @author Óscar González Fernández <ogonzalez@igalia.com>
|
||||
* @author Manuel Rego Casasnovas <rego@igalia.com>
|
||||
*/
|
||||
@Component
|
||||
@Scope(BeanDefinition.SCOPE_SINGLETON)
|
||||
|
|
@ -285,6 +288,9 @@ public class TaskElementAdapter {
|
|||
@Autowired
|
||||
private IConfigurationDAO configurationDAO;
|
||||
|
||||
@Autowired
|
||||
private IMoneyCostCalculator moneyCostCalculator;
|
||||
|
||||
static class GanttDateAdapter extends CustomDate {
|
||||
|
||||
private static final int DAY_MILLISECONDS = (int) Days.days(1)
|
||||
|
|
@ -639,6 +645,58 @@ public class TaskElementAdapter {
|
|||
RoundingMode.HALF_UP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getMoneyCostBarEndDate() {
|
||||
return calculateLimitDateProportionalToTaskElementSize(getMoneyCostBarPercentage());
|
||||
}
|
||||
|
||||
private GanttDate calculateLimitDateProportionalToTaskElementSize(
|
||||
BigDecimal proportion) {
|
||||
if (proportion.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return getBeginDate();
|
||||
}
|
||||
|
||||
IntraDayDate start = taskElement.getIntraDayStartDate();
|
||||
IntraDayDate end = taskElement.getIntraDayEndDate();
|
||||
|
||||
EffortDuration effortBetween = start.effortUntil(end);
|
||||
int seconds = new BigDecimal(effortBetween.getSeconds())
|
||||
.multiply(proportion).toBigInteger().intValue();
|
||||
return TaskElementAdapter.toGantt(
|
||||
start.addEffort(EffortDuration.seconds(seconds)),
|
||||
EffortDuration.hours(8));
|
||||
}
|
||||
|
||||
private BigDecimal getMoneyCostBarPercentage() {
|
||||
return MoneyCostCalculator.getMoneyCostProportion(
|
||||
getMoneyCost(), getBudget());
|
||||
}
|
||||
|
||||
private BigDecimal getBudget() {
|
||||
if ((taskElement == null)
|
||||
|| (taskElement.getOrderElement() == null)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return taskElement.getOrderElement().getBudget();
|
||||
}
|
||||
|
||||
private BigDecimal getMoneyCost() {
|
||||
if ((taskElement == null)
|
||||
|| (taskElement.getOrderElement() == null)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
return transactionService
|
||||
.runOnReadOnlyTransaction(new IOnTransaction<BigDecimal>() {
|
||||
|
||||
@Override
|
||||
public BigDecimal execute() {
|
||||
return moneyCostCalculator
|
||||
.getMoneyCost(taskElement
|
||||
.getOrderElement());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public GanttDate getAdvanceEndDate(String progressType) {
|
||||
return getAdvanceEndDate(ProgressType.asEnum(progressType));
|
||||
|
|
@ -1005,9 +1063,19 @@ public class TaskElementAdapter {
|
|||
result.append(_("Hours invested") + ": ")
|
||||
.append(getHoursAdvancePercentage().multiply(
|
||||
new BigDecimal(100))).append("% <br/>");
|
||||
|
||||
if (taskElement.getOrderElement() instanceof Order) {
|
||||
result.append(_("State") + ": ").append(getOrderState());
|
||||
} else {
|
||||
result.append(
|
||||
_("Budget: {0}€, Consumed: {1}€ ({2}%)",
|
||||
getBudget(),
|
||||
getMoneyCost(),
|
||||
getMoneyCostBarPercentage().multiply(
|
||||
new BigDecimal(100)))).append(
|
||||
"<br/>");
|
||||
}
|
||||
|
||||
String labels = buildLabelsText();
|
||||
if (!labels.equals("")) {
|
||||
result.append("<div class='tooltip-labels'>" + _("Labels")
|
||||
|
|
|
|||
|
|
@ -120,6 +120,8 @@ public class CompanyPlanningController implements Composer {
|
|||
|
||||
planner.setAreShownReportedHoursByDefault(Planner
|
||||
.guessShowReportedHoursByDefault(parameters));
|
||||
planner.setAreShownMoneyCostBarByDefault(Planner
|
||||
.guessShowMoneyCostBarByDefault(parameters));
|
||||
|
||||
orderFilter = (Vbox) planner.getFellow("orderFilter");
|
||||
// Configuration of the order filter
|
||||
|
|
|
|||
|
|
@ -21,7 +21,6 @@
|
|||
|
||||
package org.libreplan.web.planner.company;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.io.IOException;
|
||||
|
|
@ -96,13 +95,11 @@ import org.zkoss.ganttz.timetracker.zoom.ZoomLevel;
|
|||
import org.zkoss.ganttz.util.Emitter;
|
||||
import org.zkoss.ganttz.util.Emitter.IEmissionListener;
|
||||
import org.zkoss.ganttz.util.Interval;
|
||||
import org.zkoss.zk.au.out.AuInsertAfter;
|
||||
import org.zkoss.zk.ui.Executions;
|
||||
import org.zkoss.zk.ui.WrongValueException;
|
||||
import org.zkoss.zk.ui.event.Event;
|
||||
import org.zkoss.zk.ui.event.EventListener;
|
||||
import org.zkoss.zk.ui.event.Events;
|
||||
import org.zkoss.zk.ui.util.Clients;
|
||||
import org.zkoss.zul.Checkbox;
|
||||
import org.zkoss.zul.Datebox;
|
||||
import org.zkoss.zul.Div;
|
||||
|
|
@ -569,6 +566,7 @@ public class CompanyPlanningModel implements ICompanyPlanningModel {
|
|||
configuration.setRenamingTasksEnabled(false);
|
||||
configuration.setTreeEditable(false);
|
||||
configuration.setShowAllResourcesEnabled(false);
|
||||
configuration.setMoneyCostBarEnabled(false);
|
||||
}
|
||||
|
||||
private void addAdditionalCommands(
|
||||
|
|
|
|||
|
|
@ -178,6 +178,8 @@ public class OrderPlanningController implements Composer {
|
|||
|
||||
planner.setAreShownReportedHoursByDefault(Planner
|
||||
.guessShowReportedHoursByDefault(parameters));
|
||||
planner.setAreShownMoneyCostBarByDefault(Planner
|
||||
.guessShowMoneyCostBarByDefault(parameters));
|
||||
|
||||
orderElementFilter = (Vbox) planner.getFellow("orderElementFilter");
|
||||
// Configuration of the order filter
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ import org.libreplan.business.planner.entities.DayAssignment.FilterType;
|
|||
import org.libreplan.business.planner.entities.Dependency;
|
||||
import org.libreplan.business.planner.entities.DerivedAllocation;
|
||||
import org.libreplan.business.planner.entities.GenericResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.IMoneyCostCalculator;
|
||||
import org.libreplan.business.planner.entities.ResourceAllocation;
|
||||
import org.libreplan.business.planner.entities.ResourceAllocation.IVisitor;
|
||||
import org.libreplan.business.planner.entities.SpecificResourceAllocation;
|
||||
|
|
@ -172,6 +173,9 @@ public class PlanningStateCreator {
|
|||
@Autowired
|
||||
private IOrderAuthorizationDAO orderAuthorizationDAO;
|
||||
|
||||
@Autowired
|
||||
private IMoneyCostCalculator moneyCostCalculator;
|
||||
|
||||
void synchronizeWithSchedule(Order order, IOptionalPersistence persistence) {
|
||||
List<TaskSourceSynchronization> synchronizationsNeeded = order
|
||||
.calculateSynchronizationsNeeded();
|
||||
|
|
@ -276,6 +280,9 @@ public class PlanningStateCreator {
|
|||
currentScenario);
|
||||
|
||||
forceLoadOfWorkingHours(result.getInitial());
|
||||
|
||||
moneyCostCalculator.resetMoneyCostMap();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ import org.zkoss.zk.ui.event.Events;
|
|||
import org.zkoss.zk.ui.event.SelectEvent;
|
||||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Comboitem;
|
||||
import org.zkoss.zul.Decimalbox;
|
||||
import org.zkoss.zul.Intbox;
|
||||
import org.zkoss.zul.Listbox;
|
||||
import org.zkoss.zul.Listcell;
|
||||
|
|
@ -87,6 +88,8 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
|
||||
private Intbox duration;
|
||||
|
||||
private Decimalbox budget;
|
||||
|
||||
private Datebox startDateBox;
|
||||
|
||||
private Datebox endDateBox;
|
||||
|
|
@ -209,6 +212,7 @@ public class TaskPropertiesController extends GenericForwardComposer {
|
|||
hideResourceAllocationTypeRow();
|
||||
}
|
||||
hours.setValue(currentTaskElement.getWorkHours());
|
||||
budget.setValue(currentTaskElement.getBudget());
|
||||
Util.reloadBindings(tabpanel);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ import org.libreplan.web.common.Level;
|
|||
import org.libreplan.web.common.MessagesForUser;
|
||||
import org.libreplan.web.common.OnlyOneVisible;
|
||||
import org.libreplan.web.common.Util;
|
||||
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
|
||||
import org.libreplan.web.common.entrypoints.EntryPointsHandler;
|
||||
import org.libreplan.web.common.entrypoints.IURLHandlerRegistry;
|
||||
import org.libreplan.web.planner.tabs.IGlobalViewEntryPoints;
|
||||
import org.libreplan.web.templates.advances.AdvancesAssignmentComponent;
|
||||
import org.libreplan.web.templates.criterionrequirements.CriterionRequirementTemplateComponent;
|
||||
|
|
@ -61,6 +61,7 @@ import org.zkoss.zul.Image;
|
|||
import org.zkoss.zul.Label;
|
||||
import org.zkoss.zul.Messagebox;
|
||||
import org.zkoss.zul.Tab;
|
||||
import org.zkoss.zul.Tabpanel;
|
||||
import org.zkoss.zul.Textbox;
|
||||
import org.zkoss.zul.Tree;
|
||||
import org.zkoss.zul.Window;
|
||||
|
|
@ -374,4 +375,18 @@ public class OrderTemplatesController extends GenericForwardComposer implements
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public boolean isContainer() {
|
||||
if (model.getTemplate() == null) {
|
||||
return false;
|
||||
}
|
||||
return !model.getTemplate().isLeaf();
|
||||
}
|
||||
|
||||
public void reloadBudget() {
|
||||
Tabpanel tabPanel = (Tabpanel) editWindow
|
||||
.getFellow("tabPanelGeneralData");
|
||||
Util.reloadBindings(tabPanel);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,15 @@ public class TemplatesTreeComponent extends TreeComponent {
|
|||
renderer.addHoursCell(currentElement);
|
||||
}
|
||||
|
||||
});
|
||||
result.add(new TemplatesTreeColumn(_("Budget"), "budget") {
|
||||
|
||||
@Override
|
||||
protected void doCell(TemplatesTreeRenderer renderer,
|
||||
Treeitem item, OrderElementTemplate currentElement) {
|
||||
renderer.addBudgetCell(currentElement);
|
||||
}
|
||||
|
||||
});
|
||||
result.add(new TemplatesTreeColumn(
|
||||
_("Must start after (days since beginning project)"),
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ package org.libreplan.web.templates;
|
|||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.hibernate.validator.ClassValidator;
|
||||
import org.libreplan.business.orders.entities.SchedulingState;
|
||||
|
|
@ -272,11 +274,33 @@ public class TemplatesTreeController extends
|
|||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IBudgetHandler<OrderElementTemplate> getBudgetHandler() {
|
||||
return new IBudgetHandler<OrderElementTemplate>() {
|
||||
|
||||
@Override
|
||||
public BigDecimal getBudgetFor(OrderElementTemplate element) {
|
||||
return element.getBudget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBudgetHours(OrderElementTemplate element,
|
||||
BigDecimal budget) {
|
||||
if (element instanceof OrderLineTemplate) {
|
||||
OrderLineTemplate line = (OrderLineTemplate) element;
|
||||
line.setBudget(budget);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public void refreshRow(Treeitem item) {
|
||||
try {
|
||||
OrderElementTemplate orderElement = (OrderElementTemplate) item
|
||||
.getValue();
|
||||
getRenderer().updateHoursFor(orderElement);
|
||||
getRenderer().updateBudgetFor(orderElement);
|
||||
getRenderer().render(item, orderElement);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ package org.libreplan.web.tree;
|
|||
|
||||
import static org.libreplan.web.I18nHelper._;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
|
|
@ -62,6 +63,7 @@ import org.zkoss.zk.ui.event.KeyEvent;
|
|||
import org.zkoss.zk.ui.util.GenericForwardComposer;
|
||||
import org.zkoss.zul.Button;
|
||||
import org.zkoss.zul.Constraint;
|
||||
import org.zkoss.zul.Decimalbox;
|
||||
import org.zkoss.zul.Intbox;
|
||||
import org.zkoss.zul.RendererCtrl;
|
||||
import org.zkoss.zul.Textbox;
|
||||
|
|
@ -234,6 +236,7 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
T newNode = getModel().addElementAt(node, name.getValue(),
|
||||
hours.getValue());
|
||||
getRenderer().refreshHoursValueForThisNodeAndParents(newNode);
|
||||
getRenderer().refreshBudgetValueForThisNodeAndParents(newNode);
|
||||
|
||||
if (node.isLeaf() && !node.isEmptyLeaf()) {
|
||||
// Then a new container will be created
|
||||
|
|
@ -325,6 +328,7 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
List<T> parentNodes = getModel().getParents(element);
|
||||
getModel().removeNode(element);
|
||||
getRenderer().refreshHoursValueForNodes(parentNodes);
|
||||
getRenderer().refreshBudgetValueForNodes(parentNodes);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -578,6 +582,8 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
|
||||
private Map<T, Intbox> hoursIntBoxByElement = new HashMap<T, Intbox>();
|
||||
|
||||
private Map<T, Decimalbox> budgetDecimalboxByElement = new HashMap<T, Decimalbox>();
|
||||
|
||||
private KeyboardNavigationHandler navigationHandler = new KeyboardNavigationHandler();
|
||||
|
||||
private Treerow currentTreeRow;
|
||||
|
|
@ -771,6 +777,117 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
|
||||
protected abstract void addDescriptionCell(final T element);
|
||||
|
||||
public void addBudgetCell(final T currentElement) {
|
||||
Decimalbox decimalboxBudget = buildBudgetDecimalboxFor(currentElement);
|
||||
budgetDecimalboxByElement.put(currentElement, decimalboxBudget);
|
||||
if (readOnly) {
|
||||
decimalboxBudget.setDisabled(true);
|
||||
}
|
||||
addCell(decimalboxBudget);
|
||||
}
|
||||
|
||||
private Decimalbox buildBudgetDecimalboxFor(final T element) {
|
||||
Decimalbox result = new DecimalboxDirectValue();
|
||||
if (element.isLeaf()) {
|
||||
Util.bind(result, getBudgetGetterFor(element),
|
||||
getBudgetSetterFor(element));
|
||||
result.setConstraint(getBudgetConstraintFor(element));
|
||||
} else {
|
||||
// If it's a container budget cell is not editable
|
||||
Util.bind(result, getBudgetGetterFor(element));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private Getter<BigDecimal> getBudgetGetterFor(final T element) {
|
||||
return new Util.Getter<BigDecimal>() {
|
||||
@Override
|
||||
public BigDecimal get() {
|
||||
return getBudgetHandler().getBudgetFor(element);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Setter<BigDecimal> getBudgetSetterFor(final T element) {
|
||||
return new Util.Setter<BigDecimal>() {
|
||||
@Override
|
||||
public void set(BigDecimal value) {
|
||||
getBudgetHandler().setBudgetHours(element, value);
|
||||
List<T> parentNodes = getModel().getParents(element);
|
||||
// Remove the last element because it's an
|
||||
// Order node, not an OrderElement
|
||||
parentNodes.remove(parentNodes.size() - 1);
|
||||
for (T node : parentNodes) {
|
||||
DecimalboxDirectValue decimalbox = (DecimalboxDirectValue) budgetDecimalboxByElement
|
||||
.get(node);
|
||||
BigDecimal budget = getBudgetHandler().getBudgetFor(
|
||||
node);
|
||||
if (isInCurrentPage(decimalbox)) {
|
||||
decimalbox.setValue(budget);
|
||||
} else {
|
||||
decimalbox.setValueDirectly(budget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInCurrentPage(DecimalboxDirectValue intbox) {
|
||||
Treeitem treeItem = (Treeitem) intbox.getParent()
|
||||
.getParent().getParent();
|
||||
List<Treeitem> treeItems = new ArrayList<Treeitem>(
|
||||
tree.getItems());
|
||||
int position = treeItems.indexOf(treeItem);
|
||||
|
||||
if (position < 0) {
|
||||
throw new RuntimeException("Treeitem " + treeItem
|
||||
+ " has to belong to tree.getItems() list");
|
||||
}
|
||||
|
||||
return (position / tree.getPageSize()) == tree
|
||||
.getActivePage();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public void updateBudgetFor(T element) {
|
||||
if (!readOnly && element.isLeaf()) {
|
||||
Decimalbox decimalbox = budgetDecimalboxByElement.get(element);
|
||||
Treecell tc = (Treecell) decimalbox.getParent();
|
||||
decimalbox.invalidate();
|
||||
refreshBudgetValueForThisNodeAndParents(element);
|
||||
}
|
||||
}
|
||||
|
||||
public void refreshBudgetValueForThisNodeAndParents(T node) {
|
||||
List<T> nodeAndItsParents = getModel().getParents(node);
|
||||
nodeAndItsParents.add(node);
|
||||
refreshBudgetValueForNodes(nodeAndItsParents);
|
||||
}
|
||||
|
||||
public void refreshBudgetValueForNodes(List<T> nodes) {
|
||||
for (T node : nodes) {
|
||||
Decimalbox decimalbox = budgetDecimalboxByElement.get(node);
|
||||
// For the Order node there is no associated decimalbox
|
||||
if (decimalbox != null) {
|
||||
BigDecimal currentBudget = getBudgetHandler().getBudgetFor(node);
|
||||
decimalbox.setValue(currentBudget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Constraint getBudgetConstraintFor(final T line) {
|
||||
return new Constraint() {
|
||||
@Override
|
||||
public void validate(Component comp, Object value)
|
||||
throws WrongValueException {
|
||||
if (((BigDecimal) value).compareTo(BigDecimal.ZERO) < 0) {
|
||||
throw new WrongValueException(comp,
|
||||
_("Budget value cannot be negative"));
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
public void addHoursCell(final T currentElement) {
|
||||
Intbox intboxHours = buildHoursIntboxFor(currentElement);
|
||||
hoursIntBoxByElement.put(currentElement, intboxHours);
|
||||
|
|
@ -1057,6 +1174,15 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
|
||||
protected abstract IHoursGroupHandler<T> getHoursGroupHandler();
|
||||
|
||||
public interface IBudgetHandler<T> {
|
||||
|
||||
BigDecimal getBudgetFor(T element);
|
||||
|
||||
void setBudgetHours(T element, BigDecimal budget);
|
||||
}
|
||||
|
||||
protected abstract IBudgetHandler<T> getBudgetHandler();
|
||||
|
||||
/**
|
||||
* Disable control buttons (new, up, down, indent, unindent, delete)
|
||||
*/
|
||||
|
|
@ -1137,4 +1263,24 @@ public abstract class TreeController<T extends ITreeNode<T>> extends
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is to give visibility to method
|
||||
* {@link Decimalbox#setValueDirectly} which is marked as protected in
|
||||
* {@link Decimalbox} class.
|
||||
*
|
||||
* <br />
|
||||
*
|
||||
* This is needed to prevent calling {@link AbstractComponent#smartUpdate}
|
||||
* when the {@link Decimalbox} is not in current page. <tt>smartUpdate</tt>
|
||||
* is called by {@link Decimalbox#setValue(Integer)}. This call causes a
|
||||
* JavaScript error when trying to update {@link Decimalbox} that are not in
|
||||
* current page in the tree.
|
||||
*/
|
||||
private class DecimalboxDirectValue extends Decimalbox {
|
||||
@Override
|
||||
public void setValueDirectly(Object value) {
|
||||
super.setValueDirectly(value);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 285 B |
|
|
@ -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
|
||||
|
|
@ -153,6 +153,10 @@
|
|||
<label id="txtTotalBudget" value="@{controller.order.totalBudget}"/>
|
||||
</hbox>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Calculated budget')}" />
|
||||
<label id="budget" value="@{controller.order.budget}" />
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Total hours')}" />
|
||||
<label value="@{controller.order.totalHours}" width="200px"/>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -117,7 +117,57 @@
|
|||
value="@{assignedHoursToOrderElementController.progressWork}" />
|
||||
<label value="${i18n:_('%')}" />
|
||||
<progressmeter id="hoursProgressBar" />
|
||||
<progressmeter id="exceedHoursProgressBar" />
|
||||
<progressmeter id="exceedHoursProgressBar"
|
||||
style="background:red ; border:1px solid red"
|
||||
value="0" />
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</panelchildren>
|
||||
</panel>
|
||||
</vbox>
|
||||
|
||||
<!-- Money consumed -->
|
||||
<vbox width="100%">
|
||||
<panel
|
||||
title="${i18n:_('Percentage of estimated budget in money / money spent')}">
|
||||
<panelchildren>
|
||||
<grid fixedLayout="true">
|
||||
<columns>
|
||||
<column />
|
||||
<column />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<grid fixedLayout="true">
|
||||
<columns>
|
||||
<column width="200px" />
|
||||
<column width="200px" />
|
||||
</columns>
|
||||
<rows>
|
||||
<row>
|
||||
<label
|
||||
value="${i18n:_('Budget in money')}:" />
|
||||
<label
|
||||
value="@{assignedHoursToOrderElementController.budget}" />
|
||||
</row>
|
||||
<row>
|
||||
<label
|
||||
value="${i18n:_('Money spent')}:" />
|
||||
<label
|
||||
value="@{assignedHoursToOrderElementController.moneyCost}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
<hbox>
|
||||
<label
|
||||
value="@{assignedHoursToOrderElementController.moneyCostPercentage}" />
|
||||
<label value="${i18n:_('%')}" />
|
||||
<progressmeter id="moneyCostProgressBar" />
|
||||
<progressmeter id="exceedMoneyCostProgressBar"
|
||||
style="background:red ; border:1px solid red"
|
||||
value="0" />
|
||||
</hbox>
|
||||
</row>
|
||||
</rows>
|
||||
|
|
|
|||
|
|
@ -61,6 +61,13 @@
|
|||
value="@{detailsController.orderElement.description}"
|
||||
width="600px" />
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Budget')}" />
|
||||
<decimalbox id="budget"
|
||||
value="@{detailsController.orderElement.budget}"
|
||||
disabled="@{detailsController.container}"
|
||||
constraint="no negative:${i18n:_('Budget value cannot be negative')}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</vbox>
|
||||
|
|
|
|||
|
|
@ -258,13 +258,20 @@ div.box.limiting-unassigned {
|
|||
opacity: 0.2;
|
||||
}
|
||||
|
||||
.completionMoneyCostBar {
|
||||
width: 0%;
|
||||
height: 3px; /* zkTasklist.HEIGHT_PER_TASK / 2 */
|
||||
background-color: #009900;
|
||||
border: 0px;
|
||||
margin-top: -9px;
|
||||
}
|
||||
|
||||
.completion {
|
||||
width: 0%;
|
||||
margin-top: 0px;
|
||||
height: 3px; /* zkTasklist.HEIGHT_PER_TASK / 2 */
|
||||
background-color: #F21CFF;
|
||||
border: 0px;
|
||||
margin-top: -5px;
|
||||
margin-top: 1px;
|
||||
}
|
||||
|
||||
.completion2 {
|
||||
|
|
@ -276,7 +283,7 @@ div.box.limiting-unassigned {
|
|||
}
|
||||
|
||||
.taskcontainer_completion {
|
||||
margin-top: -16px;
|
||||
margin-top: -20px;
|
||||
}
|
||||
|
||||
.row span {
|
||||
|
|
@ -1366,4 +1373,4 @@ div.z-grid-header .second_level_ tr {
|
|||
.plannergraph .timeplot-timeflag {
|
||||
opacity: 1 !important;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,8 @@
|
|||
label="${i18n:_('Show progress')}" checked="true"/>
|
||||
<checkbox id="print_reported_hours"
|
||||
label="${i18n:_('Show all reported hours')}" checked="true"/>
|
||||
<checkbox id="print_money_cost_bar"
|
||||
label="${i18n:_('Show money cost bar')}" checked="true"/>
|
||||
</vbox>
|
||||
</groupbox>
|
||||
<hbox>
|
||||
|
|
|
|||
|
|
@ -54,10 +54,14 @@
|
|||
<label value="${i18n:_('Hours')}" />
|
||||
<intbox id="hours" disabled="true" />
|
||||
</row>
|
||||
<row id="durationRow">
|
||||
<row id="durationRow">
|
||||
<label value="${i18n:_('Duration (days)')}" />
|
||||
<intbox id="duration" disabled="true"/>
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Budget')}" />
|
||||
<decimalbox id="budget" disabled="true" />
|
||||
</row>
|
||||
<row id="startConstraint">
|
||||
<label value="${i18n:_('Constraint')}" />
|
||||
<vbox>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@
|
|||
<editTemplateWindow />
|
||||
<tabbox>
|
||||
<tabs>
|
||||
<tab id="tabGeneralData" label="${i18n:_('General data')}" />
|
||||
<tab id="tabGeneralData" label="${i18n:_('General data')}"
|
||||
onSelect="templatesForOrdersController.reloadBudget()" />
|
||||
<tab label="${i18n:_('Template Tree')}"
|
||||
disabled="@{templatesForOrdersController.templateTreeDisabled}"
|
||||
onSelect="templatesForOrdersController.openTemplateTree()" />
|
||||
|
|
@ -69,7 +70,7 @@
|
|||
<tab label="${i18n:_('Statistics log')}" />
|
||||
</tabs>
|
||||
<tabpanels>
|
||||
<tabpanel>
|
||||
<tabpanel id="tabPanelGeneralData">
|
||||
<grid fixedLayout="true">
|
||||
<columns>
|
||||
<column width="200px" />
|
||||
|
|
@ -102,6 +103,13 @@
|
|||
<textbox rows="3" width="600px"
|
||||
value="@{templatesForOrdersController.template.description}" />
|
||||
</row>
|
||||
<row>
|
||||
<label value="${i18n:_('Budget')}" />
|
||||
<decimalbox
|
||||
value="@{templatesForOrdersController.template.budget}"
|
||||
disabled="@{templatesForOrdersController.container}"
|
||||
constraint="no negative:${i18n:_('Budget value cannot be negative')}" />
|
||||
</row>
|
||||
</rows>
|
||||
</grid>
|
||||
</tabpanel>
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue