Package org.libreplan.business.orders.daos

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

/*
* 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.orders.daos;

import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

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.orders.entities.Order;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.orders.entities.OrderLineGroup;
import org.libreplan.business.orders.entities.SumChargedEffort;
import org.libreplan.business.util.Pair;
import org.libreplan.business.workingday.EffortDuration;
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.Repository;
import org.springframework.transaction.annotation.Transactional;

/**
* DAO for {@link SumChargedEffort}.
*
* @author Manuel Rego Casasnovas <rego@igalia.com>
*/
@Repository
@Scope(BeanDefinition.SCOPE_SINGLETON)
public class SumChargedEffortDAO extends
        GenericDAOHibernate<SumChargedEffort, Long> implements
        ISumChargedEffortDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Autowired
    private IWorkReportLineDAO workReportLineDAO;

    @Autowired
    private IAdHocTransactionService transactionService;

    @Autowired
    private IOrderDAO orderDAO;

    @Autowired
    private IOrderElementDAO orderElementDAO;

    private Map<OrderElement, SumChargedEffort> mapSumChargedEfforts;

    @Override
    public void updateRelatedSumChargedEffortWithWorkReportLineSet(
            Set<WorkReportLine> workReportLineSet) {
        resetMapSumChargedEfforts();

        for (WorkReportLine workReportLine : workReportLineSet) {
            updateRelatedSumChargedEffortWithAddedOrModifiedWorkReportLine(workReportLine);
        }
    }

    private void updateRelatedSumChargedEffortWithAddedOrModifiedWorkReportLine(
            final WorkReportLine workReportLine) {
        boolean increase = true;
        boolean sameOrderElement = true;
        EffortDuration effort = workReportLine.getEffort();
        OrderElement orderElement = workReportLine.getOrderElement();

        EffortDuration previousEffort = null;
        OrderElement previousOrderElement = null;

        if (!workReportLine.isNewObject()) {
            Pair<EffortDuration, OrderElement> previous = transactionService
                    .runOnAnotherTransaction(new IOnTransaction<Pair<EffortDuration, OrderElement>>() {
                        @Override
                        public Pair<EffortDuration, OrderElement> execute() {
                            try {
                                WorkReportLine line = workReportLineDAO
                                        .find(workReportLine.getId());

                                OrderElement orderElement = line
                                        .getOrderElement();
                                forceLoadParents(orderElement);

                                return Pair.create(line.getEffort(),
                                        orderElement);
                            } catch (InstanceNotFoundException e) {
                                throw new RuntimeException(e);
                            }
                        }

                        private void forceLoadParents(OrderElement orderElement) {
                            OrderLineGroup parent = orderElement.getParent();
                            if (parent != null) {
                                forceLoadParents(parent);
                            }
                        }

                    });

            previousEffort = previous.getFirst();
            previousOrderElement = previous.getSecond();

            sameOrderElement = orderElement.getId().equals(
                    previousOrderElement.getId());
        }

        if (sameOrderElement) {
            if (previousEffort != null) {
                if (effort.compareTo(previousEffort) >= 0) {
                    effort = effort.minus(previousEffort);
                } else {
                    increase = false;
                    effort = previousEffort.minus(effort);
                }
            }

            if (!effort.isZero()) {
                if (increase) {
                    addDirectChargedEffort(orderElement, effort);
                } else {
                    substractDirectChargedEffort(orderElement, effort);
                }
            }
        } else {
            substractDirectChargedEffort(previousOrderElement, previousEffort);
            addDirectChargedEffort(orderElement, effort);
        }
    }

    private void addDirectChargedEffort(OrderElement orderElement,
            EffortDuration effort) {
        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);

        sumChargedEffort.addDirectChargedEffort(effort);
        save(sumChargedEffort);

        addInirectChargedEffortRecursively(orderElement.getParent(), effort);
    }

    private void addInirectChargedEffortRecursively(OrderElement orderElement,
            EffortDuration effort) {
        if (orderElement != null) {
            SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);

            sumChargedEffort.addIndirectChargedEffort(effort);
            save(sumChargedEffort);

            addInirectChargedEffortRecursively(orderElement.getParent(), effort);
        }
    }

    @Override
    public void updateRelatedSumChargedEffortWithDeletedWorkReportLineSet(
            Set<WorkReportLine> workReportLineSet) {
        resetMapSumChargedEfforts();

        for (WorkReportLine workReportLine : workReportLineSet) {
            updateRelatedSumChargedEffortWithDeletedWorkReportLine(workReportLine);
        }
    }

    private void resetMapSumChargedEfforts() {
        mapSumChargedEfforts = new HashMap<OrderElement, SumChargedEffort>();
    }

    private void updateRelatedSumChargedEffortWithDeletedWorkReportLine(
            WorkReportLine workReportLine) {
        if (workReportLine.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(workReportLine);

        substractDirectChargedEffort(workReportLine.getOrderElement(),
                workReportLine.getEffort());
    }

    private void substractDirectChargedEffort(OrderElement orderElement,
            EffortDuration effort) {
        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);

        sumChargedEffort.subtractDirectChargedEffort(effort);
        save(sumChargedEffort);

        substractInirectChargedEffortRecursively(orderElement.getParent(),
                effort);
    }

    private void substractInirectChargedEffortRecursively(OrderElement orderElement,
            EffortDuration effort) {
        if (orderElement != null) {
            SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);

            sumChargedEffort.subtractIndirectChargedEffort(effort);
            save(sumChargedEffort);

            substractInirectChargedEffortRecursively(orderElement.getParent(), effort);
        }
    }

    private SumChargedEffort getByOrderElement(OrderElement orderElement) {
        SumChargedEffort sumChargedEffort = mapSumChargedEfforts
                .get(orderElement);
        if (sumChargedEffort == null) {
            sumChargedEffort = findByOrderElement(orderElement);
            if (sumChargedEffort == null) {
                sumChargedEffort = SumChargedEffort.create(orderElement);
            }
            mapSumChargedEfforts.put(orderElement, sumChargedEffort);
        }
        return sumChargedEffort;
    }

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

    @Override
    @Transactional
    public void recalculateSumChargedEfforts(Long orderId) {
        try {
            Order order = orderDAO.find(orderId);
            resetMapSumChargedEfforts();
            resetSumChargedEffort(order);
            calculateDirectChargedEffort(order);
            calculateTimesheetData(order);
        } catch (InstanceNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private void resetSumChargedEffort(OrderElement orderElement) {
        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
        sumChargedEffort.reset();

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

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

        EffortDuration effort = EffortDuration.zero();
        for (WorkReportLine line : workReportLineDAO
                .findByOrderElement(orderElement)) {
            effort = effort.plus(line.getEffort());
        }
        addDirectChargedEffort(orderElement, effort);
    }

    private void calculateTimesheetData(OrderElement orderElement) {
        calculateTimesheetDatesAndChildren(orderElement);
        calculateFinishedTimesheetsAndChildren(orderElement);
    }

    private Pair<Date, Date> calculateTimesheetDatesAndChildren(
            OrderElement orderElement) {
        Pair<Date, Date> minMax = workReportLineDAO
                .findMinAndMaxDatesByOrderElement(orderElement);

        Set<Date> minDates = new HashSet<Date>();
        Set<Date> maxDates = new HashSet<Date>();

        addIfNotNull(minDates, minMax.getFirst());
        addIfNotNull(maxDates, minMax.getSecond());

        for (OrderElement child : orderElement.getChildren()) {
            Pair<Date, Date> minMaxChild = calculateTimesheetDatesAndChildren(child);
            addIfNotNull(minDates, minMaxChild.getFirst());
            addIfNotNull(maxDates, minMaxChild.getSecond());
        }

        Pair<Date, Date> result = Pair.create(
                minDates.isEmpty() ? null : Collections.min(minDates),
                maxDates.isEmpty() ? null : Collections.max(maxDates));

        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
        sumChargedEffort.setTimesheetDates(result.getFirst(),
                result.getSecond());
        save(sumChargedEffort);

        return result;
    }

    private void addIfNotNull(Collection<Date> list, Date date) {
        if (date != null) {
            list.add(date);
        }
    }

    private void calculateFinishedTimesheetsAndChildren(
            OrderElement orderElement) {
        calculateFinishedTimesheets(orderElement);

        for (OrderElement child : orderElement.getChildren()) {
            calculateFinishedTimesheetsAndChildren(child);
        }
    }

    private void calculateFinishedTimesheets(OrderElement orderElement) {
        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
        sumChargedEffort.setFinishedTimesheets(workReportLineDAO
                .isFinished(orderElement));
        save(sumChargedEffort);
    }

    @Override
    @Transactional(readOnly = true)
    public Set<OrderElement> getOrderElementsToRecalculateTimsheetDates(
            Set<WorkReportLine> workReportLines,
            Set<WorkReportLine> deletedWorkReportLines) {
        Set<OrderElement> orderElements = new HashSet<OrderElement>();

        if (workReportLines != null) {
            for (final WorkReportLine workReportLine : workReportLines) {
                if (!workReportLine.isNewObject()) {
                    OrderElement previousOrderElement = transactionService
                            .runOnAnotherTransaction(new IOnTransaction<OrderElement>() {
                                @Override
                                public OrderElement execute() {
                                    try {
                                        WorkReportLine line = workReportLineDAO
                                                .find(workReportLine.getId());

                                        return line.getOrderElement();
                                    } catch (InstanceNotFoundException e) {
                                        throw new RuntimeException(e);
                                    }
                                }
                            });
                    orderElements.add(previousOrderElement);
                }
                orderElements.add(workReportLine.getOrderElement());
            }
        }

        if (deletedWorkReportLines != null) {
            for (WorkReportLine workReportLine : deletedWorkReportLines) {
                if (workReportLine.isNewObject()) {
                    // If the line hasn't been saved, we don't take it into
                    // account
                    continue;
                }

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

                orderElements.add(workReportLine.getOrderElement());
            }
        }

        return orderElements;
    }

    @Override
    @Transactional
    public void recalculateTimesheetData(Set<OrderElement> orderElements) {
        try {
            for (OrderElement orderElement : orderElements) {
                saveTimesheetDatesRecursively(orderElementDAO.find(orderElement
                        .getId()));
                calculateFinishedTimesheets(orderElementDAO.find(orderElement
                        .getId()));
            }
        } catch (InstanceNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    private void saveTimesheetDatesRecursively(OrderElement orderElement) {
        if (orderElement != null) {
            saveTimesheetDates(orderElement);
            saveTimesheetDatesRecursively(orderElement.getParent());
        }
    }

    private void saveTimesheetDates(OrderElement orderElement) {
        Pair<Date, Date> minMax = workReportLineDAO
                .findMinAndMaxDatesByOrderElement(orderElement);

        Set<Date> minDates = new HashSet<Date>();
        Set<Date> maxDates = new HashSet<Date>();

        addIfNotNull(minDates, minMax.getFirst());
        addIfNotNull(maxDates, minMax.getSecond());

        for (OrderElement child : orderElement.getChildren()) {
            SumChargedEffort childSumChargedEffort = getByOrderElement(child);
            addIfNotNull(minDates,
                    childSumChargedEffort.getFirstTimesheetDate());
            addIfNotNull(maxDates, childSumChargedEffort.getLastTimesheetDate());
        }

        Pair<Date, Date> result = Pair.create(minDates.isEmpty() ? null
                : Collections.min(minDates), maxDates.isEmpty() ? null
                : Collections.max(maxDates));

        SumChargedEffort sumChargedEffort = getByOrderElement(orderElement);
        sumChargedEffort.setTimesheetDates(result.getFirst(),
                result.getSecond());
        save(sumChargedEffort);
    }

}
TOP

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

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.