Package org.libreplan.business.orders.daos

Source Code of org.libreplan.business.orders.daos.SumExpensesDAO

/*
* This file is part of LibrePlan
*
* Copyright (C) 2012 WirelessGalicia, 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.orders.daos;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.hibernate.Hibernate;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Restrictions;
import org.libreplan.business.common.IAdHocTransactionService;
import org.libreplan.business.common.IOnTransaction;
import org.libreplan.business.common.daos.GenericDAOHibernate;
import org.libreplan.business.common.exceptions.InstanceNotFoundException;
import org.libreplan.business.expensesheet.daos.IExpenseSheetLineDAO;
import org.libreplan.business.expensesheet.entities.ExpenseSheetLine;
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.orders.entities.SumExpenses;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
* Contract for {@link SumExpensesDAO}
*
* @author Susana Montes Pedreira <smontes@wirelessgalicia.com>
*/

@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class SumExpensesDAO extends GenericDAOHibernate<SumExpenses, Long> implements
        ISumExpensesDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Autowired
    private IExpenseSheetLineDAO expenseSheetLineDAO;

    @Autowired
    private IAdHocTransactionService transactionService;

    @Autowired
    private IOrderDAO orderDAO;

    private Map<OrderElement, SumExpenses> mapSumExpenses;

    @Override
    public void updateRelatedSumExpensesWithExpenseSheetLineSet(
            Set<ExpenseSheetLine> expenseSheetLineSet) {
        resetMapSumExpenses();

        for (ExpenseSheetLine expenseSheetLine : expenseSheetLineSet) {
            updateRelatedSumExpensesWithAddedOrModifiedExpenseSheetLine(expenseSheetLine);
        }
    }

    private void updateRelatedSumExpensesWithAddedOrModifiedExpenseSheetLine(
            final ExpenseSheetLine expenseSheetLine) {
        boolean increase = true;
        BigDecimal value = expenseSheetLine.getValue();
        if (!expenseSheetLine.isNewObject()) {
            BigDecimal previousValue = transactionService
                    .runOnAnotherTransaction(new IOnTransaction<BigDecimal>() {
                        @Override
                        public BigDecimal execute() {
                            try {
                                return expenseSheetLineDAO.find(expenseSheetLine.getId())
                                        .getValue();
                            } catch (InstanceNotFoundException e) {
                                throw new RuntimeException(e);
                            }
                        }
                    });

            boolean isTaskDifferent = updateRelatedSumExpensesIfTheAssociatedTaskIsDifferent(
                    previousValue, expenseSheetLine);

            if (!isTaskDifferent) {
                if (value.compareTo(previousValue) >= 0) {
                    value = value.subtract(previousValue);
                } else {
                    increase = false;
                    value = previousValue.subtract(value);
                }
            }
        }

        if (value != null && value.compareTo(BigDecimal.ZERO) > 0) {
            if (increase) {
                addDirectExpenses(expenseSheetLine.getOrderElement(), value);
            } else {
                substractDirectExpenses(expenseSheetLine.getOrderElement(), value);
            }
        }
    }

    private boolean updateRelatedSumExpensesIfTheAssociatedTaskIsDifferent(
            BigDecimal previousValue, final ExpenseSheetLine expenseSheetLine) {
        final OrderElement task = expenseSheetLine.getOrderElement();

        OrderElement previousTask = transactionService
                .runOnAnotherTransaction(new IOnTransaction<OrderElement>() {
                    @Override
                    public OrderElement execute() {
                        try {
                            OrderElement previousTask = expenseSheetLineDAO
                                    .find(expenseSheetLine.getId())
                                    .getOrderElement();
                            if (task.getId().compareTo(previousTask.getId()) != 0) {
                                initalizeOrderElement(previousTask);
                            }
                            return previousTask;
                        } catch (InstanceNotFoundException e) {
                            throw new RuntimeException(e);
                        }
                    }
                });
        if (task.getId().compareTo(previousTask.getId()) != 0) {
            substractDirectExpenses(previousTask, previousValue);
            return true;
        }
        return false;
    }

    private void initalizeOrderElement(OrderElement orderElement) {
        Hibernate.initialize(orderElement);
        initalizeOrder(orderElement);
    }

    private void initalizeOrder(OrderElement orderElement) {
        OrderLineGroup parent = orderElement.getParent();
        while (parent != null) {
            Hibernate.initialize(parent);
            parent = parent.getParent();
        }
    }

    private void addDirectExpenses(OrderElement orderElement, BigDecimal value) {
        SumExpenses sumExpenses = getByOrderElement(orderElement);
        if (sumExpenses == null) {
            sumExpenses = SumExpenses.create(orderElement);
        }

        sumExpenses.addDirectExpenses(value);
        save(sumExpenses);

        addIndirectExpensesRecursively(orderElement.getParent(), value);
    }

    private void addIndirectExpensesRecursively(OrderElement orderElement, BigDecimal value) {
        if (orderElement != null) {
            SumExpenses sumExpenses = getByOrderElement(orderElement);
            if (sumExpenses == null) {
                sumExpenses = SumExpenses.create(orderElement);
            }

            sumExpenses.addIndirectExpenses(value);
            save(sumExpenses);

            addIndirectExpensesRecursively(orderElement.getParent(), value);
        }
    }

    @Override
    public void updateRelatedSumExpensesWithDeletedExpenseSheetLineSet(
            Set<ExpenseSheetLine> expenseSheetLineSet) {
        resetMapSumExpenses();

        for (ExpenseSheetLine expenseSheetLine : expenseSheetLineSet) {
            updateRelatedSumExpensesWithDeletedExpenseSheetLine(expenseSheetLine);
        }
    }

    private void resetMapSumExpenses() {
        mapSumExpenses = new HashMap<OrderElement, SumExpenses>();
    }

    private void updateRelatedSumExpensesWithDeletedExpenseSheetLine(
            ExpenseSheetLine expenseSheetLine) {
        if (expenseSheetLine.isNewObject()) {
            // If the line hasn't been saved, we have nothing to update
            return;
        }

        // Refresh data from database, because of changes not saved are not
        // useful for the following operations
        sessionFactory.getCurrentSession().refresh(expenseSheetLine);

        substractDirectExpenses(expenseSheetLine.getOrderElement(), expenseSheetLine.getValue());
    }

    private void substractDirectExpenses(OrderElement orderElement, BigDecimal value) {
        SumExpenses sumExpenses = getByOrderElement(orderElement);

        sumExpenses.subtractDirectExpenses(value);
        save(sumExpenses);

        substractIndirectExpensesRecursively(orderElement.getParent(), value);
    }

    private void substractIndirectExpensesRecursively(OrderElement orderElement, BigDecimal value) {
        if (orderElement != null) {
            SumExpenses sumExpenses = getByOrderElement(orderElement);

            sumExpenses.subtractIndirectExpenses(value);
            save(sumExpenses);

            substractIndirectExpensesRecursively(orderElement.getParent(), value);
        }
    }

    private SumExpenses getByOrderElement(OrderElement orderElement) {
        SumExpenses sumExpenses = mapSumExpenses.get(orderElement);
        if (sumExpenses == null) {
            sumExpenses = findByOrderElement(orderElement);
            mapSumExpenses.put(orderElement, sumExpenses);
        }
        return sumExpenses;
    }

    @Override
    public SumExpenses findByOrderElement(OrderElement orderElement) {
        return (SumExpenses) getSession().createCriteria(getEntityClass())
                .add(Restrictions.eq("orderElement", orderElement)).uniqueResult();
    }

    @Override
    @Transactional
    public void recalculateSumExpenses(Long orderId) {
        try {
            Order order = orderDAO.find(orderId);
            resetMapSumExpenses();
            resetSumExpenses(order);
            calculateDirectExpenses(order);
        } catch (InstanceNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private void resetSumExpenses(OrderElement orderElement) {
        SumExpenses sumExpenses = getByOrderElement(orderElement);
        if (sumExpenses == null) {
            sumExpenses = SumExpenses.create(orderElement);
        }
        sumExpenses.reset();

        for (OrderElement each : orderElement.getChildren()) {
            resetSumExpenses(each);
        }
    }

    private void calculateDirectExpenses(OrderElement orderElement) {
        for (OrderElement each : orderElement.getChildren()) {
            calculateDirectExpenses(each);
        }

        BigDecimal value = BigDecimal.ZERO;
        for (ExpenseSheetLine line : expenseSheetLineDAO.findByOrderElement(orderElement)) {
            value = value.add(line.getValue());
        }
        addDirectExpenses(orderElement, value);
    }
}
TOP

Related Classes of org.libreplan.business.orders.daos.SumExpensesDAO

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.