org.libreplan.business.test.orders.entities.OrderElementTest.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.business.test.orders.entities.OrderElementTest.java

Source

/*
 * This file is part of LibrePlan
 *
 * Copyright (C) 2009-2010 Fundacin para o Fomento da Calidade Industrial e
 *                         Desenvolvemento Tecnolxico de Galicia
 * Copyright (C) 2010-2011 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.orders.entities;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
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.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.UUID;

import javax.annotation.Resource;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;

import org.apache.commons.lang3.Validate;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
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.advance.bootstrap.PredefinedAdvancedTypes;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.AdvanceMeasurementComparator;
import org.libreplan.business.advance.entities.AdvanceType;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.advance.entities.IndirectAdvanceAssignment;
import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException;
import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException;
import org.libreplan.business.common.exceptions.ValidationException;
import org.libreplan.business.orders.entities.Order;
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.requirements.entities.CriterionRequirement;
import org.libreplan.business.requirements.entities.DirectCriterionRequirement;
import org.libreplan.business.requirements.entities.IndirectCriterionRequirement;
import org.libreplan.business.resources.entities.Criterion;
import org.libreplan.business.resources.entities.CriterionType;
import org.libreplan.business.resources.entities.ResourceEnum;
import org.libreplan.business.scenarios.entities.OrderVersion;
import org.libreplan.business.test.planner.entities.TaskTest;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

/**
 * Tests for {@link OrderElement}.
 * <br />
 * @author Manuel Rego Casasnovas <mrego@igalia.com>
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { BUSINESS_SPRING_CONFIG_FILE, BUSINESS_SPRING_CONFIG_TEST_FILE })
public class OrderElementTest {

    @Resource
    private IDataBootstrap defaultAdvanceTypesBootstrapListener;

    private static OrderVersion mockedOrderVersion = TaskTest.mockOrderVersion();

    @Before
    public void loadRequiredData() {
        defaultAdvanceTypesBootstrapListener.loadRequiredData();
    }

    private Matcher<BigDecimal> sameValueAs(final BigDecimal value) {
        return new BaseMatcher<BigDecimal>() {

            @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 Validator orderElementValidator = Validation.buildDefaultValidatorFactory().getValidator();

    private static OrderLine givenOrderLine(String name, String code, Integer hours) {
        OrderLine orderLine = OrderLine.createOrderLineWithUnfixedPercentage(hours);
        orderLine.setName(name);
        orderLine.setCode(code);
        orderLine.getHoursGroups().get(0).setCode("hours-group-" + UUID.randomUUID());

        return orderLine;
    }

    private static OrderLineGroup givenOrderLineGroupWithOneOrderLine(OrderVersion orderVersion, Integer hours) {
        OrderLineGroup orderLineGroup = OrderLineGroup.create();
        orderLineGroup.setName("OrderLineGroup1");
        orderLineGroup.setCode("1");
        orderLineGroup.useSchedulingDataFor(orderVersion);
        OrderLine orderLine = givenOrderLine("OrderLine1", "1.1", hours);
        orderLineGroup.add(orderLine);

        return orderLineGroup;
    }

    public static OrderLineGroup givenOrderLineGroupWithTwoOrderLines(Integer hours1, Integer hours2) {
        return givenOrderLineGroupWithTwoOrderLines(mockedOrderVersion, hours1, hours2);
    }

    public static OrderLineGroup givenOrderLineGroupWithTwoOrderLines(OrderVersion orderVersion, Integer hours1,
            Integer hours2) {

        OrderLineGroup orderLineGroup = givenOrderLineGroupWithOneOrderLine(orderVersion, hours1);

        OrderLine orderLine = givenOrderLine("OrderLine2", "1.2", hours2);

        orderLineGroup.add(orderLine);

        return orderLineGroup;
    }

    private static DirectAdvanceAssignment givenAdvanceAssignment(BigDecimal maxValue, AdvanceType advanceType) {
        DirectAdvanceAssignment advanceAssignment = DirectAdvanceAssignment.create();
        advanceAssignment.setMaxValue(maxValue);
        advanceAssignment.setAdvanceType(advanceType);
        advanceAssignment.setReportGlobalAdvance(false);

        return advanceAssignment;
    }

    public static void addAdvanceAssignmentWithoutMeasurement(OrderElement orderElement, AdvanceType advanceType,
            BigDecimal maxValue, boolean reportGlobalAdvance)

            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        DirectAdvanceAssignment advanceAssignment = givenAdvanceAssignment(maxValue, advanceType);
        advanceAssignment.setReportGlobalAdvance(reportGlobalAdvance);
        orderElement.addAdvanceAssignment(advanceAssignment);
    }

    public static void addAdvanceAssignmentWithMeasurement(OrderElement orderElement, AdvanceType advanceType,
            BigDecimal maxValue, BigDecimal currentValue, boolean reportGlobalAdvance)
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        addAdvanceAssignmentWithMeasurement(orderElement, advanceType, maxValue, currentValue, reportGlobalAdvance,
                new LocalDate());
    }

    public static void addAdvanceAssignmentWithMeasurement(OrderElement orderElement, AdvanceType advanceType,
            BigDecimal maxValue, BigDecimal currentValue, boolean reportGlobalAdvance, LocalDate date)

            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        AdvanceMeasurement advanceMeasurement = AdvanceMeasurement.create();
        advanceMeasurement.setDate(date);
        advanceMeasurement.setValue(currentValue);

        DirectAdvanceAssignment advanceAssignment = givenAdvanceAssignment(maxValue, advanceType);
        advanceAssignment.setReportGlobalAdvance(reportGlobalAdvance);

        if (reportGlobalAdvance) {
            if (orderElement.getReportGlobalAdvanceAssignment() != null) {
                orderElement.removeReportGlobalAdvanceAssignment();
            }
        }
        orderElement.addAdvanceAssignment(advanceAssignment);
        advanceAssignment.addAdvanceMeasurements(advanceMeasurement);
        advanceMeasurement.setAdvanceAssignment(advanceAssignment);
    }

    private static AdvanceType givenAdvanceType(String name) {
        BigDecimal value = new BigDecimal(5000).setScale(2);
        BigDecimal precision = new BigDecimal(10).setScale(2);
        return AdvanceType.create(name, value, true, precision, true, false);
    }

    @Test
    @Transactional
    public void checkValidPropagation() throws ValidationException {
        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);
        Set<ConstraintViolation<OrderElement>> invalidValues = orderElementValidator.validate(orderElement);
        assertTrue(invalidValues.isEmpty());

        CriterionType type = CriterionType.create("", "");
        type.setResource(ResourceEnum.WORKER);
        Criterion criterion = Criterion.create(type);
        CriterionRequirement requirement = DirectCriterionRequirement.create(criterion);
        requirement.setOrderElement(orderElement);
        orderElement.addDirectCriterionRequirement(requirement);

        invalidValues = orderElementValidator.validate(orderElement);
        assertTrue(invalidValues.isEmpty());
    }

    @Test
    @Transactional
    public void checkAdvancePercentageEmptyOrderLine() {
        OrderLine orderLine = givenOrderLine("name", "code", 1000);
        assertThat(orderLine.getAdvancePercentage(), equalTo(BigDecimal.ZERO));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderLineWithAdvanceAssignmentWithoutMeasurement()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("name", "code", 1000);

        DirectAdvanceAssignment advanceAssignment = givenAdvanceAssignment(new BigDecimal(5000),
                PredefinedAdvancedTypes.UNITS.getType());

        orderLine.addAdvanceAssignment(advanceAssignment);

        assertThat(orderLine.getAdvancePercentage(), equalTo(BigDecimal.ZERO));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderLineWithTwoAssignments1()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("name", "code", 1000);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test1"), new BigDecimal(2000),
                new BigDecimal(200), true);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test2"), new BigDecimal(1000),
                new BigDecimal(600), false);

        assertThat(orderLine.getAdvancePercentage(), sameValueAs(division.divide(10, 4)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderLineWithFutureAdvanceMeasurement()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("name", "code", 1000);

        LocalDate future = new LocalDate().plusWeeks(1);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test1"), new BigDecimal(2000),
                new BigDecimal(200), true, future);

        assertThat(orderLine.getAdvancePercentage(), sameValueAs(division.divide(4, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderLineWithTwoAssignments3()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("name", "code", 1000);

        addAdvanceAssignmentWithMeasurement(orderLine, PredefinedAdvancedTypes.UNITS.getType(),
                new BigDecimal(2000), new BigDecimal(200), false);

        addAdvanceAssignmentWithMeasurement(orderLine, PredefinedAdvancedTypes.PERCENTAGE.getType(),
                new BigDecimal(1000), new BigDecimal(600), true);

        assertThat(orderLine.getAdvancePercentage(), sameValueAs(division.divide(60, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderLineWithThreeAssignments()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("name", "code", 1000);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test1"), new BigDecimal(2000),
                new BigDecimal(200), false);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test3"), new BigDecimal(4000),
                new BigDecimal(800), true);

        addAdvanceAssignmentWithMeasurement(orderLine, givenAdvanceType("test2"), new BigDecimal(1000),
                new BigDecimal(600), false);

        assertThat(orderLine.getAdvancePercentage(), sameValueAs(division.divide(20, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLine1() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);

        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType1, new BigDecimal(1000),
                new BigDecimal(400), true);

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);

        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType2, new BigDecimal(2000),
                new BigDecimal(200), true);

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();

        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().getUnitName().equals("test1")) {
                indirectAdvanceAssignment.setReportGlobalAdvance(true);
            } else {
                indirectAdvanceAssignment.setReportGlobalAdvance(false);
            }
        }
        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(40, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLine2() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType1, new BigDecimal(1000),
                new BigDecimal(400), true);

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType2, new BigDecimal(2000),
                new BigDecimal(200), true);

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().getUnitName().equals("test2")) {
                indirectAdvanceAssignment.setReportGlobalAdvance(true);
            } else {
                indirectAdvanceAssignment.setReportGlobalAdvance(false);
            }
        }
        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(10, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLine3() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType1, new BigDecimal(1000),
                new BigDecimal(400), true);

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType2, new BigDecimal(2000),
                new BigDecimal(200), true);
        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(20, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLineSameAdvanceType()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(2000, 3000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();

        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType, new BigDecimal(1000), new BigDecimal(100),
                true);

        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType, new BigDecimal(1000), new BigDecimal(300),
                true);

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();

        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                indirectAdvanceAssignment.setReportGlobalAdvance(true);
            } else {
                indirectAdvanceAssignment.setReportGlobalAdvance(false);
            }
        }

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(20, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLineSameAdvanceTypeChildren()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(2000, 3000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();

        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType, new BigDecimal(1000), new BigDecimal(100),
                true);

        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType, new BigDecimal(1000), new BigDecimal(300),
                true);

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(PredefinedAdvancedTypes.CHILDREN.getType())) {
                indirectAdvanceAssignment.setReportGlobalAdvance(true);
            } else {
                indirectAdvanceAssignment.setReportGlobalAdvance(false);
            }
        }

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(22, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLineWithAssignments1()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLineGroup orderLineGroup = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderLineGroup.getChildren();

        addAdvanceAssignmentWithMeasurement(children.get(0), PredefinedAdvancedTypes.UNITS.getType(),
                new BigDecimal(1000), new BigDecimal(400), true);

        addAdvanceAssignmentWithMeasurement(children.get(1), PredefinedAdvancedTypes.UNITS.getType(),
                new BigDecimal(2000), new BigDecimal(200), true);

        removeReportGlobalAdvanceFromChildrenAdvance(orderLineGroup);

        addAdvanceAssignmentWithMeasurement(orderLineGroup, PredefinedAdvancedTypes.PERCENTAGE.getType(),
                new BigDecimal(100), new BigDecimal(90), true);

        assertThat(orderLineGroup.getAdvancePercentage(), sameValueAs(division.divide(90, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLineWithAssignments2()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        addAdvanceAssignmentWithMeasurement(children.get(0), PredefinedAdvancedTypes.UNITS.getType(),
                new BigDecimal(1000), new BigDecimal(400), true);

        addAdvanceAssignmentWithMeasurement(children.get(1), PredefinedAdvancedTypes.UNITS.getType(),
                new BigDecimal(2000), new BigDecimal(200), true);

        addAdvanceAssignmentWithMeasurement(orderElement, PredefinedAdvancedTypes.PERCENTAGE.getType(),
                new BigDecimal(100), new BigDecimal(90), false);

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(20, 100)));
    }

    @Test
    @Transactional
    public void checkAdvanceMeasurementMerge() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        LocalDate one = new LocalDate(2009, 9, 1);
        LocalDate two = new LocalDate(2009, 9, 2);
        LocalDate three = new LocalDate(2009, 9, 3);
        LocalDate four = new LocalDate(2009, 9, 4);
        LocalDate five = new LocalDate(2009, 9, 5);

        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();

        addAdvanceAssignmentWithMeasurements(children.get(0), advanceType, true, new BigDecimal(1000), one,
                new BigDecimal(200), three, new BigDecimal(400), five, new BigDecimal(500));

        addAdvanceAssignmentWithMeasurements(children.get(1), advanceType, true, new BigDecimal(1000), two,
                new BigDecimal(100), three, new BigDecimal(350), four, new BigDecimal(400));

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(4333, 10000)));

        Set<DirectAdvanceAssignment> directAdvanceAssignments = orderElement.getDirectAdvanceAssignments();
        assertThat(directAdvanceAssignments.size(), equalTo(0));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(2));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(2000)));

        SortedSet<AdvanceMeasurement> advanceMeasurements = advanceAssignment.getAdvanceMeasurements();
        assertThat(advanceMeasurements.size(), equalTo(5));

        ArrayList<AdvanceMeasurement> list = new ArrayList<>(advanceMeasurements);
        Collections.sort(list, new AdvanceMeasurementComparator());
        Collections.reverse(list);
        Iterator<AdvanceMeasurement> iterator = list.iterator();

        AdvanceMeasurement next = iterator.next();
        assertThat(next.getDate(), equalTo(one));
        assertThat(next.getValue(), equalTo(new BigDecimal(200)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(two));
        assertThat(next.getValue(), equalTo(new BigDecimal(300)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(three));
        assertThat(next.getValue(), equalTo(new BigDecimal(750)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(four));
        assertThat(next.getValue(), equalTo(new BigDecimal(800)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(five));
        assertThat(next.getValue(), equalTo(new BigDecimal(900)));

    }

    private static void addAdvanceAssignmentWithMeasurements(OrderElement orderElement, AdvanceType advanceType,
            boolean reportGlobalAdvance, BigDecimal maxValue, LocalDate date1, BigDecimal value1, LocalDate date2,
            BigDecimal value2, LocalDate five, BigDecimal date3)

            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        DirectAdvanceAssignment advanceAssignment = givenAdvanceAssignment(maxValue, advanceType);
        advanceAssignment.setReportGlobalAdvance(reportGlobalAdvance);

        AdvanceMeasurement advanceMeasurement1 = AdvanceMeasurement.create();
        advanceMeasurement1.setDate(date1);
        advanceMeasurement1.setValue(value1);
        advanceMeasurement1.setAdvanceAssignment(advanceAssignment);

        AdvanceMeasurement advanceMeasurement2 = AdvanceMeasurement.create();
        advanceMeasurement2.setDate(date2);
        advanceMeasurement2.setValue(value2);
        advanceMeasurement2.setAdvanceAssignment(advanceAssignment);

        AdvanceMeasurement advanceMeasurement3 = AdvanceMeasurement.create();
        advanceMeasurement3.setDate(five);
        advanceMeasurement3.setValue(date3);
        advanceMeasurement3.setAdvanceAssignment(advanceAssignment);

        orderElement.addAdvanceAssignment(advanceAssignment);
        advanceAssignment.addAdvanceMeasurements(advanceMeasurement1);
        advanceAssignment.addAdvanceMeasurements(advanceMeasurement2);
        advanceAssignment.addAdvanceMeasurements(advanceMeasurement3);
    }

    @Test
    @Transactional
    public void checkGetAdvanceAssignmentsIdempotent() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();

        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType, new BigDecimal(1000), new BigDecimal(200),
                true);

        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType, new BigDecimal(2000), new BigDecimal(400),
                true);

        Set<DirectAdvanceAssignment> directAdvanceAssignments = orderElement.getDirectAdvanceAssignments();
        assertThat(directAdvanceAssignments.size(), equalTo(0));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(2));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(3000)));

        assertThat(advanceAssignment.getAdvanceMeasurements().size(), equalTo(1));
        assertThat(advanceAssignment.getAdvanceMeasurements().iterator().next().getValue(),
                equalTo(new BigDecimal(600)));
    }

    @Test
    @Transactional
    public void checkAdvanceMeasurementMergeWithDifferentAdvanceTypes()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        LocalDate one = new LocalDate(2009, 9, 1);
        LocalDate two = new LocalDate(2009, 9, 2);
        LocalDate three = new LocalDate(2009, 9, 3);
        LocalDate four = new LocalDate(2009, 9, 4);
        LocalDate five = new LocalDate(2009, 9, 5);

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);

        addAdvanceAssignmentWithMeasurements(children.get(0), advanceType1, true, new BigDecimal(1000), one,
                new BigDecimal(200), three, new BigDecimal(400), five, new BigDecimal(500));

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);

        addAdvanceAssignmentWithMeasurements(children.get(1), advanceType2, true, new BigDecimal(1000), two,
                new BigDecimal(100), three, new BigDecimal(350), four, new BigDecimal(400));

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(4333, 10000)));

        Set<DirectAdvanceAssignment> directAdvanceAssignments = orderElement.getDirectAdvanceAssignments();
        assertThat(directAdvanceAssignments.size(), equalTo(0));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(3));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {

            if (indirectAdvanceAssignment.getAdvanceType().getUnitName()
                    .equals(PredefinedAdvancedTypes.CHILDREN.getTypeName())) {

                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(100)));

        SortedSet<AdvanceMeasurement> advanceMeasurements = advanceAssignment.getAdvanceMeasurements();
        assertThat(advanceMeasurements.size(), equalTo(5));

        ArrayList<AdvanceMeasurement> list = new ArrayList<>(advanceMeasurements);
        Collections.sort(list, new AdvanceMeasurementComparator());
        Collections.reverse(list);
        Iterator<AdvanceMeasurement> iterator = list.iterator();

        AdvanceMeasurement next = iterator.next();
        assertThat(next.getDate(), equalTo(one));

        assertThat(next.getValue(), sameValueAs(division.divide(66600, 10000)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(two));
        assertThat(next.getValue(), sameValueAs(division.divide(133300, 10000)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(three));
        assertThat(next.getValue(), sameValueAs(division.divide(366600, 10000)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(four));
        assertThat(next.getValue(), equalTo(new BigDecimal(40).setScale(4)));

        next = iterator.next();
        assertThat(next.getDate(), equalTo(five));
        assertThat(next.getValue(), sameValueAs(division.divide(4333, 100)));
    }

    @Test
    @Transactional
    public void checkGetAdvancePercentageTwoLevelOfDepth1() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLineGroup orderLineGroup_1 = OrderLineGroup.create();
        orderLineGroup_1.setName("OrderLineGroup 1");
        orderLineGroup_1.setCode("1");

        OrderLineGroup orderLineGroup_1_1 = OrderLineGroup.create();
        orderLineGroup_1_1.setName("OrderLineGroup 1.1");
        orderLineGroup_1_1.setCode("1.1");

        orderLineGroup_1.useSchedulingDataFor(mockedOrderVersion);

        OrderLine orderLine_1_1_1 = givenOrderLine("OrderLine 1.1.1", "1.1.1", 1000);

        orderLineGroup_1.add(orderLineGroup_1_1);
        orderLineGroup_1_1.add(orderLine_1_1_1);

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(orderLine_1_1_1, advanceType1, new BigDecimal(10), new BigDecimal(2),
                true);

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        removeReportGlobalAdvanceFromChildrenAdvance(orderLineGroup_1_1);
        addAdvanceAssignmentWithMeasurement(orderLineGroup_1_1, advanceType2, new BigDecimal(100),
                new BigDecimal(50), true);

        assertThat(orderLineGroup_1.getDirectAdvanceAssignments().size(), equalTo(0));
        assertThat(orderLineGroup_1.getIndirectAdvanceAssignments().size(), equalTo(3));

        assertThat(orderLineGroup_1.getAdvancePercentage(), sameValueAs(division.divide(50, 100)));
    }

    @Test
    @Transactional
    public void checkGetAdvancePercentageTwoLevelOfDepth2() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLineGroup orderLineGroup_1 = OrderLineGroup.create();
        orderLineGroup_1.setName("OrderLineGroup 1");
        orderLineGroup_1.setCode("1");
        orderLineGroup_1.useSchedulingDataFor(mockedOrderVersion);
        OrderLineGroup orderLineGroup_1_1 = OrderLineGroup.create();
        orderLineGroup_1_1.setName("OrderLineGroup 1.1");
        orderLineGroup_1_1.setCode("1.1");

        OrderLine orderLine_1_1_1 = givenOrderLine("OrderLine 1.1.1", "1.1.1", 1000);

        orderLineGroup_1.add(orderLineGroup_1_1);
        orderLineGroup_1_1.add(orderLine_1_1_1);

        AdvanceType advanceType1 = AdvanceType.create("test1", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(orderLine_1_1_1, advanceType1, new BigDecimal(10), new BigDecimal(2),
                true);

        AdvanceType advanceType2 = AdvanceType.create("test2", new BigDecimal(10000), true, new BigDecimal(1), true,
                false);
        addAdvanceAssignmentWithMeasurement(orderLineGroup_1_1, advanceType2, new BigDecimal(100),
                new BigDecimal(50), false);

        assertThat(orderLineGroup_1.getDirectAdvanceAssignments().size(), equalTo(0));
        assertThat(orderLineGroup_1.getIndirectAdvanceAssignments().size(), equalTo(3));

        assertThat(orderLineGroup_1.getAdvancePercentage(), sameValueAs(division.divide(20, 100)));
    }

    @Test
    @Transactional
    public void checkAdvancePercentageOrderGroupLineWithPercentageAdvanceType()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        AdvanceType advanceType = PredefinedAdvancedTypes.PERCENTAGE.getType();
        addAdvanceAssignmentWithMeasurement(children.get(0), advanceType, new BigDecimal(100), new BigDecimal(40),
                true);

        addAdvanceAssignmentWithMeasurement(children.get(1), advanceType, new BigDecimal(100), new BigDecimal(20),
                true);

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(2666, 10000)));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {

            if (indirectAdvanceAssignment.getAdvanceType().getUnitName()
                    .equals(PredefinedAdvancedTypes.PERCENTAGE.getTypeName())) {

                indirectAdvanceAssignment.setReportGlobalAdvance(true);
            } else {
                indirectAdvanceAssignment.setReportGlobalAdvance(false);
            }
        }
        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(26, 4)));
    }

    @Test
    @Transactional
    public void checkAdvanceMeasurementMergePercentageAdvanceType()
            throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 2000);

        List<OrderElement> children = orderElement.getChildren();

        LocalDate one = new LocalDate(2009, 9, 1);
        LocalDate two = new LocalDate(2009, 9, 2);
        LocalDate three = new LocalDate(2009, 9, 3);
        LocalDate four = new LocalDate(2009, 9, 4);
        LocalDate five = new LocalDate(2009, 9, 5);

        AdvanceType advanceType = PredefinedAdvancedTypes.PERCENTAGE.getType();

        addAdvanceAssignmentWithMeasurements(children.get(0), advanceType, true, new BigDecimal(100), two,
                new BigDecimal(10), three, new BigDecimal(20), four, new BigDecimal(40));

        addAdvanceAssignmentWithMeasurements(children.get(1), advanceType, true, new BigDecimal(100), one,
                new BigDecimal(10), four, new BigDecimal(20), five, new BigDecimal(50));

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(4666, 10000)));

        Set<DirectAdvanceAssignment> directAdvanceAssignments = orderElement.getDirectAdvanceAssignments();
        assertThat(directAdvanceAssignments.size(), equalTo(0));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(2));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(100)));

        SortedSet<AdvanceMeasurement> advanceMeasurements = advanceAssignment.getAdvanceMeasurements();
        assertThat(advanceMeasurements.size(), equalTo(5));

        ArrayList<AdvanceMeasurement> list = new ArrayList<>(advanceMeasurements);
        Collections.sort(list, new AdvanceMeasurementComparator());
        Collections.reverse(list);
        Iterator<AdvanceMeasurement> iterator = list.iterator();

        AdvanceMeasurement next = iterator.next();
        assertThat(next.getDate(), equalTo(one));
        assertThat(next.getValue(), equalTo(new BigDecimal(6)));
        // FIXME real value should be: 6.66

        next = iterator.next();
        assertThat(next.getDate(), equalTo(two));
        assertThat(next.getValue(), equalTo(new BigDecimal(9)));
        // FIXME real value should be: 10

        next = iterator.next();
        assertThat(next.getDate(), equalTo(three));
        assertThat(next.getValue(), equalTo(new BigDecimal(12)));
        // FIXME real value should be: 13.33

        next = iterator.next();
        assertThat(next.getDate(), equalTo(four));
        assertThat(next.getValue(), equalTo(new BigDecimal(24)));
        // FIXME real value should be: 26.66

        next = iterator.next();
        assertThat(next.getDate(), equalTo(five));
        assertThat(next.getValue(), equalTo(new BigDecimal(44)));
        // FIXME real value should be: 46.66

    }

    @Test
    @Transactional
    public void checkCalculateFakeOrderLineGroup1() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(5000, 1000);

        List<OrderElement> children = orderElement.getChildren();
        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();
        addAdvanceAssignmentWithoutMeasurement(children.get(0), advanceType, new BigDecimal(1000), true);

        LocalDate one = new LocalDate(2009, 9, 1);
        LocalDate two = new LocalDate(2009, 9, 2);
        LocalDate three = new LocalDate(2009, 9, 3);

        addAdvanceAssignmentWithMeasurements(children.get(1), advanceType, true, new BigDecimal(10000), one,
                new BigDecimal(100), two, new BigDecimal(1000), three, new BigDecimal(5000));

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(833, 10000)));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(2));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(11000)));
        assertThat(advanceAssignment.getAdvanceMeasurements().size(), equalTo(3));
        assertThat(advanceAssignment.getLastAdvanceMeasurement().getValue(), equalTo(new BigDecimal(5000)));

        assertThat(advanceAssignment.getAdvancePercentage(), sameValueAs(division.divide(4545, 10000)));
    }

    @Test
    @Transactional
    public void checkCalculateFakeOrderLineGroup2() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderElement orderElement = givenOrderLineGroupWithTwoOrderLines(1000, 5000);

        List<OrderElement> children = orderElement.getChildren();
        AdvanceType advanceType = PredefinedAdvancedTypes.UNITS.getType();

        LocalDate one = new LocalDate(2009, 9, 1);
        LocalDate two = new LocalDate(2009, 9, 2);
        LocalDate three = new LocalDate(2009, 9, 3);

        addAdvanceAssignmentWithMeasurements(children.get(0), advanceType, true, new BigDecimal(10000), one,
                new BigDecimal(100), two, new BigDecimal(1000), three, new BigDecimal(5000));

        addAdvanceAssignmentWithoutMeasurement(children.get(1), advanceType, new BigDecimal(1000), true);

        assertThat(orderElement.getAdvancePercentage(), sameValueAs(division.divide(833, 10000)));

        Set<IndirectAdvanceAssignment> indirectAdvanceAssignments = orderElement.getIndirectAdvanceAssignments();
        assertThat(indirectAdvanceAssignments.size(), equalTo(2));

        DirectAdvanceAssignment advanceAssignment = null;
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : indirectAdvanceAssignments) {
            if (indirectAdvanceAssignment.getAdvanceType().equals(advanceType)) {
                advanceAssignment = orderElement.calculateFakeDirectAdvanceAssignment(indirectAdvanceAssignment);
                break;
            }
        }
        assertThat(advanceAssignment.getMaxValue(), equalTo(new BigDecimal(11000)));
        assertThat(advanceAssignment.getAdvanceMeasurements().size(), equalTo(3));
        assertThat(advanceAssignment.getLastAdvanceMeasurement().getValue(), equalTo(new BigDecimal(5000)));

        assertThat(advanceAssignment.getAdvancePercentage(), sameValueAs(division.divide(4545, 10000)));
    }

    public static void removeReportGlobalAdvanceFromChildrenAdvance(OrderLineGroup orderLineGroup) {
        for (IndirectAdvanceAssignment indirectAdvanceAssignment : orderLineGroup.getIndirectAdvanceAssignments()) {

            if (indirectAdvanceAssignment.getAdvanceType().getUnitName()
                    .equals(PredefinedAdvancedTypes.CHILDREN.getTypeName())) {

                indirectAdvanceAssignment.setReportGlobalAdvance(false);
                break;
            }
        }
    }

    @Test
    @Transactional
    public void checkChangeIndirectCriterionToInvalid() {
        Order order = Order.create();
        order.useSchedulingDataFor(mockedOrderVersion);
        OrderLineGroup container1 = OrderLineGroup.create();
        container1.useSchedulingDataFor(mockedOrderVersion);
        order.add(container1);
        OrderLineGroup container2 = OrderLineGroup.create();
        container2.useSchedulingDataFor(mockedOrderVersion);
        container1.add(container2);
        OrderLine line = OrderLine.createOrderLineWithUnfixedPercentage(100);
        line.useSchedulingDataFor(mockedOrderVersion);
        container2.add(line);

        CriterionType type = CriterionType.create("", "");
        type.setResource(ResourceEnum.WORKER);
        CriterionRequirement requirement = DirectCriterionRequirement.create(Criterion.create(type));
        order.addDirectCriterionRequirement(requirement);

        assertThat(container2.getCriterionRequirements().size(), equalTo(1));

        IndirectCriterionRequirement requirementAtContainer = (IndirectCriterionRequirement) container2
                .getCriterionRequirements().iterator().next();

        container2.setValidCriterionRequirement(requirementAtContainer, false);

        assertThat(container1.getCriterionRequirements().size(), equalTo(1));
        assertTrue(container1.getCriterionRequirements().iterator().next().isValid());

        assertThat(container2.getCriterionRequirements().size(), equalTo(1));
        assertFalse(container2.getCriterionRequirements().iterator().next().isValid());

        assertThat(line.getCriterionRequirements().size(), equalTo(1));
        assertFalse(line.getCriterionRequirements().iterator().next().isValid());

        assertThat(line.getHoursGroups().size(), equalTo(1));
        assertThat(line.getHoursGroups().get(0).getCriterionRequirements().size(), equalTo(1));
        assertFalse(line.getHoursGroups().get(0).getCriterionRequirements().iterator().next().isValid());
    }

    @Test
    @Transactional
    public void checkSpreadAdvanceInOrderLine() throws DuplicateValueTrueReportGlobalAdvanceException,
            DuplicateAdvanceAssignmentForOrderElementException {

        OrderLine orderLine = givenOrderLine("element", "element-code", 100);

        AdvanceType advanceType1 = PredefinedAdvancedTypes.PERCENTAGE.getType();
        AdvanceType advanceType2 = PredefinedAdvancedTypes.UNITS.getType();

        addAdvanceAssignmentWithoutMeasurement(orderLine, advanceType1, BigDecimal.TEN, true);
        addAdvanceAssignmentWithoutMeasurement(orderLine, advanceType2, BigDecimal.TEN, false);

        assertThat(orderLine.getReportGlobalAdvanceAssignment().getAdvanceType(), equalTo(advanceType1));
        assertNotNull(orderLine.getReportGlobalAdvanceAssignment());

        orderLine.removeAdvanceAssignment(orderLine.getAdvanceAssignmentByType(advanceType1));

        assertNotNull(orderLine.getReportGlobalAdvanceAssignment());
        assertThat(orderLine.getReportGlobalAdvanceAssignment().getAdvanceType(), equalTo(advanceType2));
    }

    @Test
    @Transactional
    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)
    @Transactional
    public void checkNonNegativeBudgetInOrderLine() {
        OrderLine line = givenOrderLine("task", "code", 10);
        line.setBudget(new BigDecimal(-100));
    }

    @Test
    @Transactional
    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)));
    }

}