org.libreplan.web.planner.adaptplanning.AdaptPlanningCommand.java Source code

Java tutorial

Introduction

Here is the source code for org.libreplan.web.planner.adaptplanning.AdaptPlanningCommand.java

Source

/*
 * 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.web.planner.adaptplanning;

import static org.libreplan.web.I18nHelper._;

import java.util.Date;
import java.util.List;

import org.joda.time.LocalDate;
import org.libreplan.business.advance.bootstrap.PredefinedAdvancedTypes;
import org.libreplan.business.advance.entities.AdvanceMeasurement;
import org.libreplan.business.advance.entities.AdvanceType;
import org.libreplan.business.advance.entities.DirectAdvanceAssignment;
import org.libreplan.business.advance.exceptions.DuplicateAdvanceAssignmentForOrderElementException;
import org.libreplan.business.advance.exceptions.DuplicateValueTrueReportGlobalAdvanceException;
import org.libreplan.business.orders.entities.OrderElement;
import org.libreplan.business.planner.entities.PositionConstraintType;
import org.libreplan.business.planner.entities.ResourceAllocation;
import org.libreplan.business.planner.entities.Task;
import org.libreplan.business.planner.entities.TaskElement;
import org.libreplan.business.workingday.IntraDayDate;
import org.libreplan.web.planner.order.PlanningStateCreator.PlanningState;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.zkoss.ganttz.Planner;
import org.zkoss.ganttz.TaskComponent;
import org.zkoss.ganttz.extensions.IContext;
import org.zkoss.ganttz.util.LongOperationFeedback;
import org.zkoss.ganttz.util.LongOperationFeedback.ILongOperation;

/**
 * @author Manuel Rego Casasnovas <rego@igalia.com>
 */
@Component
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class AdaptPlanningCommand implements IAdaptPlanningCommand {

    private PlanningState planningState;

    @Override
    public String getName() {
        return _("Adapt planning according to timesheets");
    }

    @Override
    public void doAction(final IContext<TaskElement> context) {
        LongOperationFeedback.execute(context.getRelativeTo(), new ILongOperation() {

            @Override
            public String getName() {
                return _("Adapting planning according to timesheets");
            }

            @Override
            public void doAction() throws Exception {
                adaptPlanning(context);
            }
        });
    }

    private void adaptPlanning(IContext<TaskElement> context) {
        List<TaskElement> taskElements = planningState.getRootTask().getAllChildren();
        for (TaskElement taskElement : taskElements) {
            // Only adapt task leafs
            if (!taskElement.isTask()) {
                continue;
            }

            OrderElement orderElement = taskElement.getOrderElement();
            // Reset status to allow move the task if needed while adapting the
            // planning
            taskElement.setUpdatedFromTimesheets(false);

            if (orderElement.hasTimesheetsReportingHours()) {
                setStartDateAndConstraint(taskElement, orderElement.getFirstTimesheetDate());
                Date lastTimesheetDate = orderElement.getLastTimesheetDate();
                setEndDateIfNeeded(taskElement, lastTimesheetDate);

                if (orderElement.isFinishedTimesheets()) {
                    setEndDate(taskElement, lastTimesheetDate);
                    addTimesheetsProgress(orderElement, lastTimesheetDate);
                    removeResourceAllocationsBeyondEndDate(taskElement);
                } else {
                    removeTimesheetsProgressIfAny(orderElement);
                }

                taskElement.setUpdatedFromTimesheets(true);
            } else {
                removeTimesheetsProgressIfAny(orderElement);
            }
        }
        for (TaskElement taskElement : taskElements) {
            if (taskElement.isUpdatedFromTimesheets()) {
                updateTask(context, taskElement);
            }
        }

        ((Planner) context.getRelativeTo()).invalidate();
        context.reloadCharts();
    }

    private void removeResourceAllocationsBeyondEndDate(TaskElement taskElement) {
        LocalDate endDate = taskElement.getEndAsLocalDate();

        for (ResourceAllocation<?> resourceAllocation : taskElement.getAllResourceAllocations()) {
            resourceAllocation.removeDayAssignmentsBeyondDate(endDate);
        }
    }

    private void setStartDateAndConstraint(TaskElement taskElement, Date startDate) {
        taskElement.setStartDate(startDate);
        setStartInFixedDateConstarint(taskElement, startDate);
    }

    private void setStartInFixedDateConstarint(TaskElement taskElement, Date startDate) {
        if (taskElement.isTask()) {
            Task task = (Task) taskElement;
            task.getPositionConstraint().update(PositionConstraintType.START_IN_FIXED_DATE,
                    IntraDayDate.startOfDay(LocalDate.fromDateFields(startDate)));
        }
    }

    private void setEndDateIfNeeded(TaskElement taskElement, Date endDate) {
        if (taskElement.getEndDate().compareTo(endDate) <= 0) {
            setEndDate(taskElement, endDate);
        }
    }

    private void setEndDate(TaskElement taskElement, Date endDate) {
        taskElement.setEndDate(LocalDate.fromDateFields(endDate).plusDays(1).toDateTimeAtStartOfDay().toDate());
    }

    private void addTimesheetsProgress(OrderElement orderElement, Date progressDate) {
        AdvanceType timesheetsAdvanceType = getTimesheetsAdvanceType();

        DirectAdvanceAssignment timesheetsAdvanceAssignment = orderElement
                .getDirectAdvanceAssignmentByType(timesheetsAdvanceType);

        if (timesheetsAdvanceAssignment == null) {
            timesheetsAdvanceAssignment = DirectAdvanceAssignment.create(false,
                    timesheetsAdvanceType.getDefaultMaxValue());
            timesheetsAdvanceAssignment.setAdvanceType(timesheetsAdvanceType);
            try {
                orderElement.addAdvanceAssignment(timesheetsAdvanceAssignment);
            } catch (DuplicateValueTrueReportGlobalAdvanceException e) {
                // This shouldn't happen as the new advanceAssignment is not
                // marked as spread yet
                throw new RuntimeException(e);
            } catch (DuplicateAdvanceAssignmentForOrderElementException e) {
                // If the same type already exists in other element we don't do
                // anything
                return;
            }
        }

        DirectAdvanceAssignment spreadAdvanceAssignment = orderElement.getReportGlobalAdvanceAssignment();
        if (spreadAdvanceAssignment != null) {
            spreadAdvanceAssignment.setReportGlobalAdvance(false);
        }

        timesheetsAdvanceAssignment.setReportGlobalAdvance(true);
        timesheetsAdvanceAssignment.resetAdvanceMeasurements(AdvanceMeasurement
                .create(LocalDate.fromDateFields(progressDate), timesheetsAdvanceType.getDefaultMaxValue()));
    }

    private AdvanceType getTimesheetsAdvanceType() {
        return PredefinedAdvancedTypes.TIMESHEETS.getType();
    }

    private void removeTimesheetsProgressIfAny(OrderElement orderElement) {
        DirectAdvanceAssignment timesheetsAdvanceAssignment = orderElement
                .getDirectAdvanceAssignmentByType(getTimesheetsAdvanceType());
        if (timesheetsAdvanceAssignment != null) {
            orderElement.removeAdvanceAssignment(timesheetsAdvanceAssignment);
        }
    }

    private void updateTask(IContext<TaskElement> context, TaskElement taskElement) {
        taskElement.updateAdvancePercentageFromOrderElement();

        Planner planner = (Planner) context.getRelativeTo();
        org.zkoss.ganttz.data.Task task = context.getMapper().findAssociatedBean(taskElement);
        task.firePropertyChangeForTaskDates();
        TaskComponent taskComponent = planner.getTaskComponentRelatedTo(task);
        if (taskComponent != null) {
            taskComponent.updateTooltipText();
            taskComponent.updateProperties();
            taskComponent.invalidate();
        }

        context.recalculatePosition(taskElement);
    }

    @Override
    public String getImage() {
        return "/common/img/ico_adapt_planning.png";
    }

    @Override
    public boolean isDisabled() {
        return false;
    }

    @Override
    public void setState(PlanningState planningState) {
        this.planningState = planningState;
    }

    @Override
    public boolean isPlannerCommand() {
        return true;
    }

}