diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java index e3fd28927..dba00e32d 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/orders/daos/OrderElementDAO.java @@ -21,6 +21,7 @@ package org.navalplanner.business.orders.daos; import java.math.BigDecimal; +import java.math.MathContext; import java.math.RoundingMode; import java.util.ArrayList; import java.util.HashMap; @@ -342,7 +343,8 @@ public class OrderElementDAO extends IntegrationEntityDAO private BigDecimal average(BigDecimal divisor, BigDecimal sum) { BigDecimal average = new BigDecimal(0); if (sum.compareTo(new BigDecimal(0)) > 0) { - average = sum.divide(divisor, RoundingMode.HALF_UP); + average = sum.divide(divisor, new MathContext(2, + RoundingMode.HALF_UP)); } return average; } diff --git a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java index 9b3868aba..3213260bb 100644 --- a/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java +++ b/navalplanner-business/src/main/java/org/navalplanner/business/planner/entities/HoursCostCalculator.java @@ -21,6 +21,8 @@ package org.navalplanner.business.planner.entities; import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.List; import java.util.SortedMap; import java.util.SortedSet; @@ -79,8 +81,9 @@ public class HoursCostCalculator implements ICostCalculator { if(((filterStartDate == null) || day.compareTo(filterStartDate) >= 0) && ((filterEndDate == null) || day.compareTo(filterEndDate) <= 0)) { BigDecimal cost = advanceMeasurement.getValue().setScale(2) - .multiply(new BigDecimal(totalHours)).divide( - new BigDecimal(100)); + .multiply(new BigDecimal(totalHours)) + .divide(new BigDecimal(100), + new MathContext(2, RoundingMode.HALF_UP)); result.put(day, cost); } } diff --git a/navalplanner-business/src/test/java/org/navalplanner/business/test/orders/entities/OrderElementTest.java b/navalplanner-business/src/test/java/org/navalplanner/business/test/orders/entities/OrderElementTest.java index 582f2f140..3e3ec4d3f 100644 --- a/navalplanner-business/src/test/java/org/navalplanner/business/test/orders/entities/OrderElementTest.java +++ b/navalplanner-business/src/test/java/org/navalplanner/business/test/orders/entities/OrderElementTest.java @@ -27,6 +27,8 @@ import static org.navalplanner.business.BusinessGlobalNames.BUSINESS_SPRING_CONF import static org.navalplanner.business.test.BusinessGlobalNames.BUSINESS_SPRING_CONFIG_TEST_FILE; import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -37,6 +39,10 @@ import java.util.UUID; import javax.annotation.Resource; +import org.apache.commons.lang.Validate; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.hamcrest.Matcher; import org.hibernate.validator.ClassValidator; import org.hibernate.validator.InvalidValue; import org.joda.time.LocalDate; @@ -88,6 +94,46 @@ public class OrderElementTest { defaultAdvanceTypesBootstrapListener.loadRequiredData(); } + private Matcher sameValueAs(final BigDecimal value) { + return new BaseMatcher() { + + @Override + public boolean matches(Object value) { + if (value instanceof BigDecimal) { + BigDecimal other = (BigDecimal) value; + return ((BigDecimal) value).compareTo(other) == 0; + } + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText("must have the same value as " + value); + } + }; + } + + private static class Division { + private final MathContext mathContext; + + private Division(MathContext mathContext) { + Validate.notNull(mathContext); + this.mathContext = mathContext; + } + + public BigDecimal divide(int dividend, int divisor) { + return new BigDecimal(dividend).divide(new BigDecimal(divisor), + mathContext); + } + } + + private Division division(int numberOfDecimals) { + return new Division(new MathContext(numberOfDecimals, + RoundingMode.HALF_UP)); + } + + private Division division = division(4); + private ClassValidator orderElementValidator = new ClassValidator(OrderElement.class); @@ -258,9 +304,8 @@ public class OrderElementTest { addAvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test2"), new BigDecimal(1000), new BigDecimal(600), false); - - assertThat(orderLine.getAdvancePercentage(), equalTo(new BigDecimal(10) - .setScale(4).divide(new BigDecimal(100)))); + assertThat(orderLine.getAdvancePercentage(), + sameValueAs(division.divide(10, 4))); } @Test @@ -274,8 +319,8 @@ public class OrderElementTest { givenAdvanceType("test1"), new BigDecimal(2000), new BigDecimal(200), true, future); - assertThat(orderLine.getAdvancePercentage(), equalTo(new BigDecimal(10) - .setScale(4).divide(new BigDecimal(100)))); + assertThat(orderLine.getAdvancePercentage(), + sameValueAs(division.divide(4, 100))); } @Test @@ -292,8 +337,8 @@ public class OrderElementTest { PredefinedAdvancedTypes.PERCENTAGE.getType(), new BigDecimal( 1000), new BigDecimal(600), true); - assertThat(orderLine.getAdvancePercentage(), equalTo(new BigDecimal(60) - .setScale(4).divide(new BigDecimal(100)))); + assertThat(orderLine.getAdvancePercentage(), + sameValueAs(division.divide(60, 100))); } @Test @@ -314,8 +359,8 @@ public class OrderElementTest { givenAdvanceType("test2"), new BigDecimal(1000), new BigDecimal(600), false); - assertThat(orderLine.getAdvancePercentage(), equalTo(new BigDecimal(20) - .setScale(4).divide(new BigDecimal(100)))); + assertThat(orderLine.getAdvancePercentage(), + sameValueAs(division.divide(20, 100))); } @Test @@ -347,9 +392,8 @@ public class OrderElementTest { indirectAdvanceAssignment.setReportGlobalAdvance(false); } } - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 40).setScale(4).divide(new BigDecimal(100)))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(40, 100))); } @Test @@ -381,9 +425,8 @@ public class OrderElementTest { indirectAdvanceAssignment.setReportGlobalAdvance(false); } } - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 10).setScale(4).divide(new BigDecimal(100)))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(10, 100))); } @Test @@ -404,9 +447,8 @@ public class OrderElementTest { 10000), true, new BigDecimal(1), true, false); addAvanceAssignmentWithMeasurement(children.get(1), advanceType2, new BigDecimal(2000), new BigDecimal(200), true); - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 20).divide(new BigDecimal(100)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(20, 100))); } @Test @@ -436,8 +478,8 @@ public class OrderElementTest { } } - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 20).setScale(4).divide(new BigDecimal(100)))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(20, 100))); } @Test @@ -468,8 +510,8 @@ public class OrderElementTest { } } - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 22).divide(new BigDecimal(100)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(22, 100))); } @Test @@ -494,8 +536,7 @@ public class OrderElementTest { 100), new BigDecimal(90), true); assertThat(orderLineGroup.getAdvancePercentage(), - equalTo(new BigDecimal(90).setScale(4).divide( - new BigDecimal(100)))); + sameValueAs(division.divide(90, 100))); } @Test @@ -516,9 +557,8 @@ public class OrderElementTest { addAvanceAssignmentWithMeasurement(orderElement, PredefinedAdvancedTypes.PERCENTAGE.getType(), new BigDecimal( 100), new BigDecimal(90), false); - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 20).divide(new BigDecimal(100)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(20, 100))); } @Test @@ -546,8 +586,8 @@ public class OrderElementTest { new BigDecimal(1000), two, new BigDecimal(100), three, new BigDecimal(350), four, new BigDecimal(400)); - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 4333).divide(new BigDecimal(10000)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(4333, 10000))); Set directAdvanceAssignments = orderElement .getDirectAdvanceAssignments(); @@ -700,9 +740,8 @@ public class OrderElementTest { addAvanceAssignmentWithMeasurements(children.get(1), advanceType2, true, new BigDecimal(1000), two, new BigDecimal(100), three, new BigDecimal(350), four, new BigDecimal(400)); - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 4333).divide(new BigDecimal(10000)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(4333, 10000))); Set directAdvanceAssignments = orderElement .getDirectAdvanceAssignments(); @@ -736,18 +775,16 @@ public class OrderElementTest { AdvanceMeasurement next = iterator.next(); assertThat(next.getDate(), equalTo(one)); - assertThat(next.getValue(), equalTo(new BigDecimal(66600).setScale(4) - .divide(new BigDecimal(10000)))); + + assertThat(next.getValue(), sameValueAs(division.divide(66600, 10000))); next = iterator.next(); assertThat(next.getDate(), equalTo(two)); - assertThat(next.getValue(), equalTo(new BigDecimal(133300).setScale(4) - .divide(new BigDecimal(10000)))); + assertThat(next.getValue(), sameValueAs(division.divide(133300, 10000))); next = iterator.next(); assertThat(next.getDate(), equalTo(three)); - assertThat(next.getValue(), equalTo(new BigDecimal(366600).setScale(4) - .divide(new BigDecimal(10000)))); + assertThat(next.getValue(), sameValueAs(division.divide(366600, 10000))); next = iterator.next(); assertThat(next.getDate(), equalTo(four)); @@ -755,8 +792,7 @@ public class OrderElementTest { next = iterator.next(); assertThat(next.getDate(), equalTo(five)); - assertThat(next.getValue(), equalTo(new BigDecimal(4333).setScale(4) - .divide(new BigDecimal(100)))); + assertThat(next.getValue(), sameValueAs(division.divide(4333, 100))); } @Test @@ -794,9 +830,9 @@ public class OrderElementTest { equalTo(0)); assertThat(orderLineGroup_1.getIndirectAdvanceAssignments().size(), equalTo(3)); + assertThat(orderLineGroup_1.getAdvancePercentage(), - equalTo(new BigDecimal(50).setScale(4).divide( - new BigDecimal(100)))); + sameValueAs(division.divide(50, 100))); } @Test @@ -831,9 +867,9 @@ public class OrderElementTest { equalTo(0)); assertThat(orderLineGroup_1.getIndirectAdvanceAssignments().size(), equalTo(3)); + assertThat(orderLineGroup_1.getAdvancePercentage(), - equalTo(new BigDecimal(20).setScale(4).divide( - new BigDecimal(100)))); + sameValueAs(division.divide(20, 100))); } @Test @@ -852,8 +888,8 @@ public class OrderElementTest { addAvanceAssignmentWithMeasurement(children.get(1), advanceType, new BigDecimal(100), new BigDecimal(20), true); - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 2666).divide(new BigDecimal(10000)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(2666, 10000))); Set indirectAdvanceAssignments = ((OrderLineGroup) orderElement) .getIndirectAdvanceAssignments(); @@ -865,9 +901,8 @@ public class OrderElementTest { indirectAdvanceAssignment.setReportGlobalAdvance(false); } } - - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 26).setScale(4).divide(new BigDecimal(100)))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(26, 4))); } @Test @@ -895,8 +930,8 @@ public class OrderElementTest { new BigDecimal(100), one, new BigDecimal(10), four, new BigDecimal(20), five, new BigDecimal(50)); - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 4666).setScale(4).divide(new BigDecimal(10000)))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(4666, 10000))); Set directAdvanceAssignments = orderElement .getDirectAdvanceAssignments(); @@ -974,8 +1009,8 @@ public class OrderElementTest { new BigDecimal(10000), one, new BigDecimal(100), two, new BigDecimal(1000), three, new BigDecimal(5000)); - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 833).divide(new BigDecimal(10000)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(833, 10000))); Set indirectAdvanceAssignments = ((OrderLineGroup) orderElement) .getIndirectAdvanceAssignments(); @@ -995,9 +1030,9 @@ public class OrderElementTest { equalTo(3)); assertThat(advanceAssignment.getLastAdvanceMeasurement().getValue(), equalTo(new BigDecimal(5000))); + assertThat(advanceAssignment.getAdvancePercentage(), - equalTo(new BigDecimal(4545).divide(new BigDecimal(10000)) - .setScale(4))); + sameValueAs(division.divide(4545, 10000))); } @Test @@ -1021,8 +1056,8 @@ public class OrderElementTest { addAvanceAssignmentWithoutMeasurement(children.get(1), advanceType, new BigDecimal(1000), true); - assertThat(orderElement.getAdvancePercentage(), equalTo(new BigDecimal( - 833).divide(new BigDecimal(10000)).setScale(4))); + assertThat(orderElement.getAdvancePercentage(), + sameValueAs(division.divide(833, 10000))); Set indirectAdvanceAssignments = ((OrderLineGroup) orderElement) .getIndirectAdvanceAssignments(); @@ -1042,9 +1077,9 @@ public class OrderElementTest { equalTo(3)); assertThat(advanceAssignment.getLastAdvanceMeasurement().getValue(), equalTo(new BigDecimal(5000))); + assertThat(advanceAssignment.getAdvancePercentage(), - equalTo(new BigDecimal(4545).divide(new BigDecimal(10000)) - .setScale(4))); + sameValueAs(division.divide(4545, 10000))); } public static void removeReportGlobalAdvanceFromChildrenAdvance( diff --git a/navalplanner-webapp/src/main/java/org/navalplanner/web/montecarlo/MonteCarloTask.java b/navalplanner-webapp/src/main/java/org/navalplanner/web/montecarlo/MonteCarloTask.java index ea2d26a07..0c9c75b60 100644 --- a/navalplanner-webapp/src/main/java/org/navalplanner/web/montecarlo/MonteCarloTask.java +++ b/navalplanner-webapp/src/main/java/org/navalplanner/web/montecarlo/MonteCarloTask.java @@ -1,6 +1,8 @@ package org.navalplanner.web.montecarlo; import java.math.BigDecimal; +import java.math.MathContext; +import java.math.RoundingMode; import org.apache.commons.lang.Validate; import org.joda.time.Days; @@ -175,9 +177,12 @@ public class MonteCarloTask { return BigDecimal.ZERO; } + private static final MathContext mathContext = new MathContext(2, + RoundingMode.HALF_UP); + public BigDecimal getPessimisticDurationPercentageUpperLimit() { return BigDecimal.valueOf(pessimisticDurationPercentage).divide( - BigDecimal.valueOf(100)); + BigDecimal.valueOf(100), mathContext); } public BigDecimal getNormalDurationPercentageLowerLimit() { @@ -187,7 +192,7 @@ public class MonteCarloTask { public BigDecimal getNormalDurationPercentageUpperLimit() { BigDecimal result = BigDecimal.valueOf(pessimisticDurationPercentage + normalDurationPercentage); - return result.divide(BigDecimal.valueOf(100)); + return result.divide(BigDecimal.valueOf(100), mathContext); } public BigDecimal getOptimisticDurationPercentageLowerLimit() {