controllers.core.PortfolioEntryStatusReportingController.java Source code

Java tutorial

Introduction

Here is the source code for controllers.core.PortfolioEntryStatusReportingController.java

Source

/*! LICENSE
 *
 * Copyright (c) 2015, The Agile Factory SA and/or its affiliates. All rights
 * reserved.
 *
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation; version 2 of the License.
 *
 * 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 General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program. If not, see <http://www.gnu.org/licenses/>.
 */
package controllers.core;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.inject.Inject;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.tuple.Pair;

import com.avaje.ebean.ExpressionList;

import be.objectify.deadbolt.java.actions.Dynamic;
import constants.IMafConstants;
import controllers.ControllersUtils;
import dao.pmo.ActorDao;
import dao.pmo.PortfolioEntryDao;
import dao.pmo.PortfolioEntryEventDao;
import dao.pmo.PortfolioEntryReportDao;
import dao.pmo.PortfolioEntryRiskDao;
import dao.reporting.ReportingDao;
import dao.timesheet.TimesheetDao;
import framework.security.ISecurityService;
import framework.services.account.IPreferenceManagerPlugin;
import framework.services.configuration.II18nMessagesPlugin;
import framework.services.custom_attribute.ICustomAttributeManagerService;
import framework.services.notification.INotificationManagerPlugin;
import framework.services.session.IUserSessionManagerPlugin;
import framework.services.storage.IAttachmentManagerPlugin;
import framework.services.storage.IPersonalStoragePlugin;
import framework.services.system.ISysAdminUtils;
import framework.utils.CssValueForValueHolder;
import framework.utils.DefaultSelectableValueHolderCollection;
import framework.utils.FileAttachmentHelper;
import framework.utils.FilterConfig;
import framework.utils.Msg;
import framework.utils.Pagination;
import framework.utils.Table;
import framework.utils.TableExcelRenderer;
import framework.utils.Utilities;
import models.framework_models.account.NotificationCategory;
import models.framework_models.account.NotificationCategory.Code;
import models.framework_models.common.Attachment;
import models.pmo.Actor;
import models.pmo.PortfolioEntry;
import models.pmo.PortfolioEntryEvent;
import models.pmo.PortfolioEntryReport;
import models.pmo.PortfolioEntryRisk;
import models.reporting.Reporting;
import models.reporting.Reporting.Format;
import models.timesheet.TimesheetLog;
import play.Configuration;
import play.Logger;
import play.data.Form;
import play.libs.F.Function0;
import play.libs.F.Promise;
import play.libs.Json;
import play.mvc.Controller;
import play.mvc.Result;
import play.mvc.With;
import scala.concurrent.duration.Duration;
import security.CheckPortfolioEntryExists;
import services.datasyndication.IDataSyndicationService;
import services.datasyndication.models.DataSyndicationAgreementItem;
import services.datasyndication.models.DataSyndicationAgreementLink;
import services.tableprovider.ITableProvider;
import utils.form.AttachmentFormData;
import utils.form.PortfolioEntryEventFormData;
import utils.form.PortfolioEntryReportFormData;
import utils.form.PortfolioEntryRiskFormData;
import utils.reporting.IReportingUtils;
import utils.table.AttachmentListView;
import utils.table.PortfolioEntryEventListView;
import utils.table.PortfolioEntryReportListView;
import utils.table.PortfolioEntryRiskListView;
import utils.table.TimesheetLogListView;

/**
 * The controller which allows to manage the status reporting (events, risks,
 * reports...) of a portfolio entry.
 * 
 * @author Johann Kohler
 */
public class PortfolioEntryStatusReportingController extends Controller {
    @Inject
    private INotificationManagerPlugin notificationManagerPlugin;
    @Inject
    private IPersonalStoragePlugin personalStoragePlugin;
    @Inject
    private IUserSessionManagerPlugin userSessionManagerPlugin;
    @Inject
    private IPreferenceManagerPlugin preferenceManagerPlugin;
    @Inject
    private IReportingUtils reportingUtils;
    @Inject
    private ISysAdminUtils sysAdminUtils;
    @Inject
    private II18nMessagesPlugin i18nMessagesPlugin;
    @Inject
    private IAttachmentManagerPlugin attachmentManagerPlugin;
    @Inject
    private ISecurityService securityService;
    @Inject
    private IDataSyndicationService dataSyndicationService;
    @Inject
    private Configuration configuration;
    @Inject
    private ITableProvider tableProvider;
    @Inject
    private ICustomAttributeManagerService customAttributeManagerService;

    private static Logger.ALogger log = Logger.of(PortfolioEntryStatusReportingController.class);

    public static Form<PortfolioEntryReportFormData> reportFormTemplate = Form
            .form(PortfolioEntryReportFormData.class);
    public static Form<PortfolioEntryRiskFormData> riskFormTemplate = Form.form(PortfolioEntryRiskFormData.class);
    public static Form<PortfolioEntryEventFormData> eventFormTemplate = Form
            .form(PortfolioEntryEventFormData.class);
    private static Form<AttachmentFormData> attachmentFormTemplate = Form.form(AttachmentFormData.class);

    /**
     * Export the actor allocation.
     * 
     * @param id
     *            the actor id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result exportStatusReport(Long id) {

        Pair<String, Format> reportNameAndFormat = getReportStatusTemplateNameAndFormat();

        Reporting report = ReportingDao.getReportingByTemplate(reportNameAndFormat.getLeft());

        // construct the report parameters
        Map<String, Object> reportParameters = new HashMap<String, Object>();
        reportParameters.put("REPORT_" + reportNameAndFormat.getLeft().toUpperCase() + "_PORTFOLIO_ENTRY", id);

        getReportingUtils().generate(ctx(), report, getI18nMessagesPlugin().getCurrentLanguage().getCode(),
                reportNameAndFormat.getRight(), reportParameters);

        Utilities.sendSuccessFlashMessage(Msg.get("core.reporting.generate.request.success"));

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController.registers(id, 0, 0, 0,
                false, false));
    }

    /**
     * Display the registers (list of reports, risk and issues) of a portfolio
     * entry.
     * 
     * note: risks and issues are stored in the same DB table
     * (portfolio_entry_risk), this is the flag has_occured that determines if
     * it's a risk (false) or an issue (true)
     * 
     * @param id
     *            the portfolio entry id
     * @param pageReports
     *            the current page for reports table
     * @param pageRisks
     *            the current page for the risks table
     * @param pageIssues
     *            the current page for the issues table
     * @param viewAllRisks
     *            set to true if all risks (including the inactive) must be
     *            displayed
     * @param viewAllIssues
     *            set to true if all issues (including the inactive) must be
     *            displayed
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result registers(Long id, Integer pageReports, Integer pageRisks, Integer pageIssues,
            Boolean viewAllRisks, Boolean viewAllIssues) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the reports

        Pagination<PortfolioEntryReport> reportsPagination = PortfolioEntryReportDao.getPEReportAsPaginationByPE(id,
                true);
        reportsPagination.setPageQueryName("pageReports");
        reportsPagination.setCurrentPage(pageReports);

        List<PortfolioEntryReportListView> portfolioEntryReportsListView = new ArrayList<PortfolioEntryReportListView>();
        for (PortfolioEntryReport portfolioEntryReport : reportsPagination.getListOfObjects()) {
            portfolioEntryReportsListView.add(new PortfolioEntryReportListView(portfolioEntryReport));
        }

        Set<String> hideColumnsForReport = new HashSet<String>();
        if (!getSecurityService().dynamic("PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION", "")) {
            hideColumnsForReport.add("editActionLink");
            hideColumnsForReport.add("deleteActionLink");
        }

        Table<PortfolioEntryReportListView> filledReportsTable = this.getTableProvider()
                .get().portfolioEntryReport.templateTable.fill(portfolioEntryReportsListView, hideColumnsForReport);

        // get the syndicated reports
        List<DataSyndicationAgreementLink> agreementLinks = new ArrayList<>();
        DataSyndicationAgreementItem agreementItem = null;
        if (portfolioEntry.isSyndicated && dataSyndicationService.isActive()) {
            try {
                agreementItem = dataSyndicationService
                        .getAgreementItemByDataTypeAndDescriptor(PortfolioEntry.class.getName(), "REPORT");
                if (agreementItem != null) {
                    agreementLinks = dataSyndicationService.getAgreementLinksOfItemAndSlaveObject(agreementItem,
                            PortfolioEntry.class.getName(), id);
                }
            } catch (Exception e) {
                Logger.error("impossible to get the syndicated report data", e);
            }
        }

        // get the portfolioEntry risks

        Pagination<PortfolioEntryRisk> risksPagination = PortfolioEntryRiskDao.getPERiskAsPaginationByPE(id,
                viewAllRisks);
        risksPagination.setPageQueryName("pageRisks");
        risksPagination.setCurrentPage(pageRisks);

        List<PortfolioEntryRiskListView> portfolioEntryRisksListView = new ArrayList<PortfolioEntryRiskListView>();
        for (PortfolioEntryRisk portfolioEntryRisk : risksPagination.getListOfObjects()) {
            portfolioEntryRisksListView.add(new PortfolioEntryRiskListView(portfolioEntryRisk));
        }

        Set<String> hideColumnsForRisk = new HashSet<String>();
        hideColumnsForRisk.add("isMitigated");
        hideColumnsForRisk.add("dueDate");
        if (!getSecurityService().dynamic("PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION", "")) {
            hideColumnsForRisk.add("editActionLink");
        }

        Table<PortfolioEntryRiskListView> filledRisksTable = this.getTableProvider()
                .get().portfolioEntryRisk.templateTable.fill(portfolioEntryRisksListView, hideColumnsForRisk);

        // get the portfolioEntry issues

        Pagination<PortfolioEntryRisk> issuesPagination = PortfolioEntryRiskDao.getPEIssueAsPaginationByPE(id,
                viewAllIssues);
        issuesPagination.setPageQueryName("pageIssues");
        issuesPagination.setCurrentPage(pageIssues);

        List<PortfolioEntryRiskListView> portfolioEntryIssuesListView = new ArrayList<PortfolioEntryRiskListView>();
        for (PortfolioEntryRisk portfolioEntryRisk : issuesPagination.getListOfObjects()) {
            portfolioEntryIssuesListView.add(new PortfolioEntryRiskListView(portfolioEntryRisk));
        }

        Set<String> hideColumnsForIssue = new HashSet<String>();
        hideColumnsForIssue.add("isMitigated");
        hideColumnsForIssue.add("targetDate");
        if (!getSecurityService().dynamic("PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION", "")) {
            hideColumnsForIssue.add("editActionLink");
        }

        Table<PortfolioEntryRiskListView> filledIssuesTable = this.getTableProvider()
                .get().portfolioEntryRisk.templateTable.fill(portfolioEntryIssuesListView, hideColumnsForIssue);

        // get the report in order to know if it is active
        Reporting report = ReportingDao.getReportingByTemplate(getReportStatusTemplateNameAndFormat().getLeft());

        return ok(views.html.core.portfolioentrystatusreporting.registers.render(portfolioEntry, filledReportsTable,
                reportsPagination, filledRisksTable, risksPagination, filledIssuesTable, issuesPagination,
                viewAllRisks, viewAllIssues, report.isActive, agreementLinks, agreementItem));
    }

    /**
     * Display the list of events.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result events(Long id) {

        // get the portfolio entry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        try {

            // get the filter config
            String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
            FilterConfig<PortfolioEntryEventListView> filterConfig = this.getTableProvider()
                    .get().portfolioEntryEvent.filterConfig.getCurrent(uid, request());

            // get the table
            Pair<Table<PortfolioEntryEventListView>, Pagination<PortfolioEntryEvent>> t = getEventsTable(id,
                    filterConfig);

            return ok(views.html.core.portfolioentrystatusreporting.events.render(portfolioEntry, t.getLeft(),
                    t.getRight(), filterConfig));

        } catch (Exception e) {

            return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                    getI18nMessagesPlugin());

        }
    }

    /**
     * Filter the events.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result eventsFilter(Long id) {

        try {

            // get the filter config
            String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
            FilterConfig<PortfolioEntryEventListView> filterConfig = this.getTableProvider()
                    .get().portfolioEntryEvent.filterConfig.persistCurrentInDefault(uid, request());

            if (filterConfig == null) {
                return ok(views.html.framework_views.parts.table.dynamic_tableview_no_more_compatible.render());
            } else {

                // get the table
                Pair<Table<PortfolioEntryEventListView>, Pagination<PortfolioEntryEvent>> t = getEventsTable(id,
                        filterConfig);

                return ok(
                        views.html.framework_views.parts.table.dynamic_tableview.render(t.getLeft(), t.getRight()));

            }

        } catch (Exception e) {
            return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                    getI18nMessagesPlugin());
        }
    }

    /**
     * Export the content of the current events table as Excel.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Promise<Result> exportEventsAsExcel(final Long id) {

        return Promise.promise(new Function0<Result>() {
            @Override
            public Result apply() throws Throwable {

                try {

                    // Get the current user
                    final String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());

                    // construct the table
                    FilterConfig<PortfolioEntryEventListView> filterConfig = getTableProvider()
                            .get().portfolioEntryEvent.filterConfig.getCurrent(uid, request());

                    ExpressionList<PortfolioEntryEvent> expressionList = filterConfig
                            .updateWithSearchExpression(PortfolioEntryEventDao.getPEEventAsExprByPE(id));
                    filterConfig.updateWithSortExpression(expressionList);

                    List<PortfolioEntryEventListView> portfolioEntryEventListView = new ArrayList<PortfolioEntryEventListView>();
                    for (PortfolioEntryEvent portfolioEntryEvent : expressionList.findList()) {
                        portfolioEntryEventListView.add(new PortfolioEntryEventListView(portfolioEntryEvent));
                    }

                    Table<PortfolioEntryEventListView> table = getTableProvider()
                            .get().portfolioEntryEvent.templateTable.fillForFilterConfig(
                                    portfolioEntryEventListView, filterConfig.getColumnsToHide());

                    final byte[] excelFile = TableExcelRenderer.renderFormatted(table);

                    final String fileName = String.format("eventsExport_%1$td_%1$tm_%1$ty_%1$tH-%1$tM-%1$tS.xlsx",
                            new Date());
                    final String successTitle = Msg.get("excel.export.success.title");
                    final String successMessage = Msg.get("excel.export.success.message", fileName);
                    final String failureTitle = Msg.get("excel.export.failure.title");
                    final String failureMessage = Msg.get("excel.export.failure.message");

                    // Execute asynchronously
                    getSysAdminUtils().scheduleOnce(false, "Events Excel Export",
                            Duration.create(0, TimeUnit.MILLISECONDS), new Runnable() {
                                @Override
                                public void run() {

                                    try {
                                        OutputStream out = getPersonalStoragePlugin().createNewFile(uid, fileName);
                                        IOUtils.copy(new ByteArrayInputStream(excelFile), out);
                                        getNotificationManagerPlugin().sendNotification(uid,
                                                NotificationCategory.getByCode(Code.DOCUMENT), successTitle,
                                                successMessage,
                                                controllers.my.routes.MyPersonalStorage.index().url());
                                    } catch (IOException e) {
                                        log.error("Unable to export the excel file", e);
                                        getNotificationManagerPlugin().sendNotification(uid,
                                                NotificationCategory.getByCode(Code.ISSUE), failureTitle,
                                                failureMessage,
                                                controllers.core.routes.PortfolioEntryStatusReportingController
                                                        .events(id).url());
                                    }
                                }
                            });

                    return ok(Json.newObject());

                } catch (Exception e) {
                    return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                            getI18nMessagesPlugin());
                }
            }
        });

    }

    /**
     * Get the events table for a portfolio entry and a filter config.
     * 
     * @param portfolioEntryId
     *            the portfolio entry id
     * @param filterConfig
     *            the filter config.
     */
    private Pair<Table<PortfolioEntryEventListView>, Pagination<PortfolioEntryEvent>> getEventsTable(
            Long portfolioEntryId, FilterConfig<PortfolioEntryEventListView> filterConfig) {

        ExpressionList<PortfolioEntryEvent> expressionList = filterConfig
                .updateWithSearchExpression(PortfolioEntryEventDao.getPEEventAsExprByPE(portfolioEntryId));
        filterConfig.updateWithSortExpression(expressionList);

        Pagination<PortfolioEntryEvent> pagination = new Pagination<PortfolioEntryEvent>(
                this.getPreferenceManagerPlugin(), expressionList);
        pagination.setCurrentPage(filterConfig.getCurrentPage());

        List<PortfolioEntryEventListView> portfolioEntryEventListView = new ArrayList<PortfolioEntryEventListView>();
        for (PortfolioEntryEvent event : pagination.getListOfObjects()) {
            portfolioEntryEventListView.add(new PortfolioEntryEventListView(event));
        }

        Set<String> hideColumnsForEvent = filterConfig.getColumnsToHide();
        if (!getSecurityService().dynamic("PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION", "")) {
            hideColumnsForEvent.add("editActionLink");
            hideColumnsForEvent.add("deleteActionLink");
        }

        Table<PortfolioEntryEventListView> table = this.getTableProvider().get().portfolioEntryEvent.templateTable
                .fillForFilterConfig(portfolioEntryEventListView, hideColumnsForEvent);

        return Pair.of(table, pagination);

    }

    /**
     * Display the details of a portfolio entry report.
     * 
     * @param id
     *            the portfolio entry id
     * @param reportId
     *            the report id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result viewReport(Long id, Long reportId) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the portfolio entry report
        PortfolioEntryReport portfolioEntryReport = PortfolioEntryReportDao.getPEReportById(reportId);

        // construct the corresponding form data (for the custom attributes)
        PortfolioEntryReportFormData portfolioEntryReportFormData = new PortfolioEntryReportFormData(
                portfolioEntryReport);

        // security: the portfolioEntry must be related to the object
        if (!portfolioEntryReport.portfolioEntry.id.equals(id)) {
            return forbidden(views.html.error.access_forbidden.render(""));
        }

        /*
         * Get the attachments
         */

        // authorize the attachments
        FileAttachmentHelper.getFileAttachmentsForDisplay(PortfolioEntryReport.class, reportId,
                getAttachmentManagerPlugin(), getUserSessionManagerPlugin());

        // create the table
        List<Attachment> attachments = Attachment
                .getAttachmentsFromObjectTypeAndObjectId(PortfolioEntryReport.class, reportId);

        List<AttachmentListView> attachmentsListView = new ArrayList<AttachmentListView>();
        for (Attachment attachment : attachments) {
            attachmentsListView.add(new AttachmentListView(attachment,
                    controllers.core.routes.PortfolioEntryStatusReportingController
                            .deleteReportAttachment(id, reportId, attachment.id).url()));
        }

        Set<String> hideColumns = new HashSet<String>();
        if (!getSecurityService().dynamic("PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION", "")) {
            hideColumns.add("removeActionLink");
        }

        Table<AttachmentListView> attachmentsTable = this.getTableProvider().get().attachment.templateTable
                .fill(attachmentsListView, hideColumns);

        return ok(views.html.core.portfolioentrystatusreporting.report_view.render(portfolioEntry,
                portfolioEntryReport, portfolioEntryReportFormData, attachmentsTable));
    }

    /**
     * Form to edit/create a new report for a portfolio entry.
     * 
     * @param id
     *            the portfolio entry id
     * @param reportId
     *            the report id (set to 0 for create case)
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result manageReport(Long id, Long reportId) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // initiate the form with the template
        Form<PortfolioEntryReportFormData> reportForm = reportFormTemplate;

        // edit case: inject values
        if (!reportId.equals(Long.valueOf(0))) {
            PortfolioEntryReport portfolioEntryReport = PortfolioEntryReportDao.getPEReportById(reportId);

            // security: the portfolioEntry must be related to the object
            if (!portfolioEntryReport.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            reportForm = reportFormTemplate.fill(new PortfolioEntryReportFormData(portfolioEntryReport));

            // add the custom attributes values
            this.getCustomAttributeManagerService().fillWithValues(reportForm, PortfolioEntryReport.class,
                    reportId);

        } else {

            reportForm = reportFormTemplate.fill(new PortfolioEntryReportFormData());

            // add the custom attributes default values
            this.getCustomAttributeManagerService().fillWithValues(reportForm, PortfolioEntryReport.class, null);
        }

        // get the selectable portfolioEntry report status types
        DefaultSelectableValueHolderCollection<CssValueForValueHolder> selectablePortfolioEntryReportStatusTypes = PortfolioEntryReportDao
                .getPEReportStatusTypeActiveAsCssVH();

        return ok(views.html.core.portfolioentrystatusreporting.report_manage.render(portfolioEntry,
                selectablePortfolioEntryReportStatusTypes, reportForm));
    }

    /**
     * Perform the save for a new/update report.
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result processManageReport() {

        // bind the form
        Form<PortfolioEntryReportFormData> boundForm = reportFormTemplate.bindFromRequest();

        // get the portfolioEntry
        Long id = Long.valueOf(boundForm.data().get("id"));
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        if (boundForm.hasErrors()
                || this.getCustomAttributeManagerService().validateValues(boundForm, PortfolioEntryReport.class)) {

            // get the selectable portfolioEntry report status types
            DefaultSelectableValueHolderCollection<CssValueForValueHolder> selectablePortfolioEntryReportStatusTypes = PortfolioEntryReportDao
                    .getPEReportStatusTypeActiveAsCssVH();

            return ok(views.html.core.portfolioentrystatusreporting.report_manage.render(portfolioEntry,
                    selectablePortfolioEntryReportStatusTypes, boundForm));
        }

        PortfolioEntryReportFormData portfolioEntryReportFormData = boundForm.get();

        PortfolioEntryReport portfolioEntryReport = null;

        // create case
        if (portfolioEntryReportFormData.reportId == null) {

            portfolioEntryReport = new PortfolioEntryReport();
            portfolioEntryReport.portfolioEntry = portfolioEntry;
            portfolioEntryReport.isPublished = true;
            portfolioEntryReport.creationDate = new Date();
            portfolioEntryReport.publicationDate = portfolioEntryReport.creationDate;

            // get the current actor
            String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
            Actor actor = ActorDao.getActorByUid(uid);
            if (actor == null) {
                return redirect(controllers.dashboard.routes.DashboardController.index(0, false));
            }

            portfolioEntryReport.author = actor;

            portfolioEntryReportFormData.fill(portfolioEntryReport);

            portfolioEntryReport.save();

            portfolioEntry.lastPortfolioEntryReport = portfolioEntryReport;
            portfolioEntry.save();

            // if exists, add the document
            if (FileAttachmentHelper.hasFileField("document")) {
                Logger.debug("has document");
                try {
                    FileAttachmentHelper.saveAsAttachement("document", PortfolioEntryReport.class,
                            portfolioEntryReport.id, getAttachmentManagerPlugin());
                } catch (IOException e) {
                    Logger.error("impossible to add the document for the created report '" + portfolioEntryReport.id
                            + "'. The report still created.", e);
                }
            }

            Utilities.sendSuccessFlashMessage(
                    Msg.get("core.portfolio_entry_status_reporting.report.add.successful"));

        } else { // edit case

            portfolioEntryReport = PortfolioEntryReportDao.getPEReportById(portfolioEntryReportFormData.reportId);

            // security: the portfolioEntry must be related to the object
            if (!portfolioEntryReport.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            portfolioEntryReportFormData.fill(portfolioEntryReport);
            portfolioEntryReport.update();

            Utilities.sendSuccessFlashMessage(
                    Msg.get("core.portfolio_entry_status_reporting.report.edit.successful"));
        }

        // save the custom attributes
        this.getCustomAttributeManagerService().validateAndSaveValues(boundForm, PortfolioEntryReport.class,
                portfolioEntryReport.id);

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController
                .registers(portfolioEntryReportFormData.id, 0, 0, 0, false, false));
    }

    /**
     * Delete a report.
     * 
     * @param id
     *            the portfolio entry id
     * @param reportId
     *            the report id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result deleteReport(Long id, Long reportId) {

        // get the portfolio entry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the report
        PortfolioEntryReport portfolioEntryReport = PortfolioEntryReportDao.getPEReportById(reportId);

        // security: the portfolioEntry must be related to the object
        if (!portfolioEntryReport.portfolioEntry.id.equals(id)) {
            return forbidden(views.html.error.access_forbidden.render(""));
        }

        // set the delete flag to true
        portfolioEntryReport.doDelete();

        // if necessary update the last report of the PE
        if (portfolioEntry.lastPortfolioEntryReport.id.equals(portfolioEntryReport.id)) {
            portfolioEntry.lastPortfolioEntryReport = PortfolioEntryReportDao.getPEReportAsLastByPE(id);
            portfolioEntry.save();
        }

        Utilities
                .sendSuccessFlashMessage(Msg.get("core.portfolio_entry_status_reporting.report.delete.successful"));

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController.registers(id, 0, 0, 0,
                false, false));

    }

    /**
     * Form to add an attachment to a report.
     * 
     * @param id
     *            the portfolio entry id
     * @param reportId
     *            the report id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result createReportAttachment(Long id, Long reportId) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the report
        PortfolioEntryReport report = PortfolioEntryReportDao.getPEReportById(reportId);

        // construct the form
        Form<AttachmentFormData> attachmentForm = attachmentFormTemplate.fill(new AttachmentFormData());

        return ok(views.html.core.portfolioentrystatusreporting.report_attachment_create.render(portfolioEntry,
                report, attachmentForm));

    }

    /**
     * Process the form to add an attachment to a report.
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result processCreateReportAttachment() {

        Form<AttachmentFormData> boundForm = attachmentFormTemplate.bindFromRequest();

        // get the portfolioEntry
        Long id = Long.valueOf(boundForm.data().get("id"));
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the report
        Long reportId = Long.valueOf(boundForm.data().get("objectId"));
        PortfolioEntryReport report = PortfolioEntryReportDao.getPEReportById(reportId);

        if (boundForm.hasErrors()) {
            return ok(views.html.core.portfolioentrystatusreporting.report_attachment_create.render(portfolioEntry,
                    report, boundForm));
        }

        // store the document
        try {
            FileAttachmentHelper.saveAsAttachement("document", PortfolioEntryReport.class, report.id,
                    getAttachmentManagerPlugin());
        } catch (Exception e) {
            return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                    getI18nMessagesPlugin());
        }

        // success message
        Utilities.sendSuccessFlashMessage(Msg.get("core.portfolio_entry.attachment.new.successful"));

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController
                .viewReport(portfolioEntry.id, report.id));
    }

    /**
     * Delete an attachment of a report.
     * 
     * @param id
     *            the portfolio entry id
     * @param reportId
     *            the report id
     * @param attachmentId
     *            the attachment id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result deleteReportAttachment(Long id, Long reportId, Long attachmentId) {

        // get the report
        PortfolioEntryReport report = PortfolioEntryReportDao.getPEReportById(reportId);

        // get the attachment
        Attachment attachment = Attachment.getAttachmentFromId(attachmentId);

        // security: the report must be related to the attachment, and
        // the portfolio entry to the report
        if (!attachment.objectId.equals(reportId) || !report.portfolioEntry.id.equals(id)) {
            return forbidden(views.html.error.access_forbidden.render(""));
        }

        // delete the attachment
        FileAttachmentHelper.deleteFileAttachment(attachmentId, getAttachmentManagerPlugin(),
                getUserSessionManagerPlugin());

        attachment.doDelete();

        Utilities.sendSuccessFlashMessage(Msg.get("core.portfolio_entry.attachment.delete"));

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController.viewReport(id, reportId));

    }

    /**
     * Display the details of a portfolio entry risk/issue.
     * 
     * @param id
     *            the portfolio entry id
     * @param riskId
     *            the risk/issue id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result viewRisk(Long id, Long riskId) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // get the portfolioEntry risk
        PortfolioEntryRisk portfolioEntryRisk = PortfolioEntryRiskDao.getPERiskById(riskId);

        // construct the corresponding form data (for the custom attributes)
        PortfolioEntryRiskFormData portfolioEntryRiskFormData = new PortfolioEntryRiskFormData(portfolioEntryRisk);

        // security: the portfolioEntry must be related to the object
        if (!portfolioEntryRisk.portfolioEntry.id.equals(id)) {
            return forbidden(views.html.error.access_forbidden.render(""));
        }

        return ok(views.html.core.portfolioentrystatusreporting.risk_view.render(portfolioEntry, portfolioEntryRisk,
                portfolioEntryRiskFormData));
    }

    /**
     * Form to create/edit a risk/issue.
     * 
     * @param id
     *            the portfolio entry id
     * @param riskId
     *            the risk/issue id (set to 0 for create case)
     * @param isRisk
     *            set to true if it's a risk, else this is an issue (this flag
     *            is useful for the create case)
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result manageRisk(Long id, Long riskId, Boolean isRisk) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // initiate the form with the template
        Form<PortfolioEntryRiskFormData> riskForm = riskFormTemplate;

        // initiate the form data
        PortfolioEntryRiskFormData portfolioEntryRiskFormData = null;

        // edit case: get the portfolioEntry risk instance
        if (!riskId.equals(Long.valueOf(0))) {
            PortfolioEntryRisk portfolioEntryRisk = PortfolioEntryRiskDao.getPERiskById(riskId);

            // security: the portfolioEntry must be related to the object
            if (!portfolioEntryRisk.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            isRisk = !portfolioEntryRisk.hasOccured;
            portfolioEntryRiskFormData = new PortfolioEntryRiskFormData(portfolioEntryRisk);

        } else { // create case: set default values
            portfolioEntryRiskFormData = new PortfolioEntryRiskFormData();
            portfolioEntryRiskFormData.isActive = true;
        }

        riskForm = riskFormTemplate.fill(portfolioEntryRiskFormData);

        if (!riskId.equals(Long.valueOf(0))) {
            // add the custom attributes values
            this.getCustomAttributeManagerService().fillWithValues(riskForm, PortfolioEntryRisk.class, riskId);
        } else {
            // add the custom attributes default values
            this.getCustomAttributeManagerService().fillWithValues(riskForm, PortfolioEntryRisk.class, null);
        }

        return ok(views.html.core.portfolioentrystatusreporting.risk_manage.render(portfolioEntry, riskForm,
                PortfolioEntryRiskDao.getPERiskTypeActiveAsVH(), isRisk));
    }

    /**
     * Perform the save for a new/update risk/issue.
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result processManageRisk() {

        // bind the form
        Form<PortfolioEntryRiskFormData> boundForm = riskFormTemplate.bindFromRequest();

        // get the portfolioEntry
        Long id = Long.valueOf(request().body().asFormUrlEncoded().get("id")[0]);
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        if (boundForm.hasErrors()
                || this.getCustomAttributeManagerService().validateValues(boundForm, PortfolioEntryRisk.class)) {
            Boolean isRisk = Boolean.valueOf(request().body().asFormUrlEncoded().get("isRisk")[0]);
            return ok(views.html.core.portfolioentrystatusreporting.risk_manage.render(portfolioEntry, boundForm,
                    PortfolioEntryRiskDao.getPERiskTypeActiveAsVH(), isRisk));
        }

        PortfolioEntryRiskFormData portfolioEntryRiskFormData = boundForm.get();

        PortfolioEntryRisk portfolioEntryRisk = null;

        // create case
        if (portfolioEntryRiskFormData.riskId == null) {

            portfolioEntryRisk = new PortfolioEntryRisk();
            portfolioEntryRisk.creationDate = new Date();
            portfolioEntryRisk.portfolioEntry = portfolioEntry;

            if (portfolioEntryRiskFormData.isRisk) {
                portfolioEntryRiskFormData.fillRisk(portfolioEntryRisk);
            } else {
                portfolioEntryRiskFormData.fillIssue(portfolioEntryRisk);
            }

            portfolioEntryRisk.save();

            if (portfolioEntryRiskFormData.isRisk) {
                Utilities.sendSuccessFlashMessage(
                        Msg.get("core.portfolio_entry_status_reporting.risk.add.successful"));
            } else {
                Utilities.sendSuccessFlashMessage(
                        Msg.get("core.portfolio_entry_status_reporting.issue.add.successful"));
            }

        } else { // edit case

            portfolioEntryRisk = PortfolioEntryRiskDao.getPERiskById(portfolioEntryRiskFormData.riskId);

            // security: the portfolioEntry must be related to the object
            if (!portfolioEntryRisk.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            if (portfolioEntryRiskFormData.isRisk) {
                portfolioEntryRiskFormData.fillRisk(portfolioEntryRisk);
            } else {
                portfolioEntryRiskFormData.fillIssue(portfolioEntryRisk);
            }
            portfolioEntryRisk.update();

            if (portfolioEntryRiskFormData.isRisk) {
                Utilities.sendSuccessFlashMessage(
                        Msg.get("core.portfolio_entry_status_reporting.risk.edit.successful"));
            } else {
                Utilities.sendSuccessFlashMessage(
                        Msg.get("core.portfolio_entry_status_reporting.issue.edit.successful"));
            }

        }

        // save the custom attributes
        this.getCustomAttributeManagerService().validateAndSaveValues(boundForm, PortfolioEntryRisk.class,
                portfolioEntryRisk.id);

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController
                .registers(portfolioEntryRiskFormData.id, 0, 0, 0, false, false));
    }

    /**
     * Form to edit/create a new event for a portfolio entry.
     * 
     * @param id
     *            the portfolio entry id
     * @param eventId
     *            the event id (set to 0 for create case)
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result manageEvent(Long id, Long eventId) {

        // get the portfolioEntry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        // initiate the form with the template
        Form<PortfolioEntryEventFormData> eventForm = eventFormTemplate;

        // edit case: get the portfolio entry event instance
        if (!eventId.equals(Long.valueOf(0))) {

            PortfolioEntryEvent portfolioEntryEvent = PortfolioEntryEventDao.getPEEventById(eventId);

            // security: the portfolio entry must be related to the object
            if (!portfolioEntryEvent.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            eventForm = eventFormTemplate.fill(new PortfolioEntryEventFormData(portfolioEntryEvent));

            // add the custom attributes values
            this.getCustomAttributeManagerService().fillWithValues(eventForm, PortfolioEntryEvent.class, eventId);

        } else {
            // add the custom attributes default values
            this.getCustomAttributeManagerService().fillWithValues(eventForm, PortfolioEntryEvent.class, null);
        }

        return ok(views.html.core.portfolioentrystatusreporting.event_manage.render(portfolioEntry, eventForm,
                PortfolioEntryEventDao.getPEEventTypeActiveAsVH()));
    }

    /**
     * Perform the save for a new/update event.
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result processManageEvent() {

        // bind the form
        Form<PortfolioEntryEventFormData> boundForm = eventFormTemplate.bindFromRequest();

        // get the portfolioEntry
        Long id = Long.valueOf(request().body().asFormUrlEncoded().get("id")[0]);
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        if (boundForm.hasErrors()
                || this.getCustomAttributeManagerService().validateValues(boundForm, PortfolioEntryEvent.class)) {
            return ok(views.html.core.portfolioentrystatusreporting.event_manage.render(portfolioEntry, boundForm,
                    PortfolioEntryEventDao.getPEEventTypeActiveAsVH()));
        }

        PortfolioEntryEventFormData portfolioEntryEventFormData = boundForm.get();

        PortfolioEntryEvent portfolioEntryEvent = null;

        // create case
        if (portfolioEntryEventFormData.eventId == null) {

            portfolioEntryEvent = new PortfolioEntryEvent();
            portfolioEntryEvent.creationDate = new Date();
            portfolioEntryEvent.portfolioEntry = portfolioEntry;

            // try to get the current actor
            try {

                String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
                portfolioEntryEvent.actor = ActorDao.getActorByUid(uid);
            } catch (Exception e) {
                return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                        getI18nMessagesPlugin());
            }

            portfolioEntryEventFormData.fill(portfolioEntryEvent);
            portfolioEntryEvent.save();

            Utilities
                    .sendSuccessFlashMessage(Msg.get("core.portfolio_entry_status_reporting.event.add.successful"));

        } else { // edit case

            portfolioEntryEvent = PortfolioEntryEventDao.getPEEventById(portfolioEntryEventFormData.eventId);

            // security: the portfolio entry must be related to the object
            if (!portfolioEntryEvent.portfolioEntry.id.equals(id)) {
                return forbidden(views.html.error.access_forbidden.render(""));
            }

            portfolioEntryEventFormData.fill(portfolioEntryEvent);
            portfolioEntryEvent.update();

            Utilities.sendSuccessFlashMessage(
                    Msg.get("core.portfolio_entry_status_reporting.event.edit.successful"));

        }

        // save the custom attributes
        this.getCustomAttributeManagerService().validateAndSaveValues(boundForm, PortfolioEntryEvent.class,
                portfolioEntryEvent.id);

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController
                .events(portfolioEntryEventFormData.id));
    }

    /**
     * Delete an event of a portfolio entry.
     * 
     * @param id
     *            the portfolio entry id
     * @param eventId
     *            the event id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_EDIT_DYNAMIC_PERMISSION)
    public Result deleteEvent(Long id, Long eventId) {

        // get the event
        PortfolioEntryEvent event = PortfolioEntryEventDao.getPEEventById(eventId);

        // security: the portfolio entry must be related to the object
        if (!event.portfolioEntry.id.equals(id)) {
            return forbidden(views.html.error.access_forbidden.render(""));
        }

        // set the delete flag to true
        event.doDelete();

        Utilities.sendSuccessFlashMessage(Msg.get("core.portfolio_entry_status_reporting.event.delete.successful"));

        return redirect(controllers.core.routes.PortfolioEntryStatusReportingController.events(id));

    }

    /**
     * Display the list of timesheet logs.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result timesheets(Long id) {

        // get the portfolio entry
        PortfolioEntry portfolioEntry = PortfolioEntryDao.getPEById(id);

        try {

            // get the filter config
            String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
            FilterConfig<TimesheetLogListView> filterConfig = this.getTableProvider()
                    .get().timesheetLog.filterConfig.getCurrent(uid, request());

            // get the table
            Pair<Table<TimesheetLogListView>, Pagination<TimesheetLog>> t = getTimesheetsTable(id, filterConfig);

            // get the syndicated timesheets
            List<DataSyndicationAgreementLink> agreementLinks = new ArrayList<>();
            DataSyndicationAgreementItem agreementItem = null;
            if (portfolioEntry.isSyndicated && dataSyndicationService.isActive()) {
                try {
                    agreementItem = dataSyndicationService
                            .getAgreementItemByDataTypeAndDescriptor(PortfolioEntry.class.getName(), "TIMESHEET");
                    if (agreementItem != null) {
                        agreementLinks = dataSyndicationService.getAgreementLinksOfItemAndSlaveObject(agreementItem,
                                PortfolioEntry.class.getName(), id);
                    }
                } catch (Exception e) {
                    Logger.error("impossible to get the syndicated timesheet data", e);
                }
            }

            return ok(views.html.core.portfolioentrystatusreporting.timesheets.render(portfolioEntry, t.getLeft(),
                    t.getRight(), filterConfig, agreementLinks, agreementItem));

        } catch (Exception e) {

            return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                    getI18nMessagesPlugin());

        }
    }

    /**
     * Filter the timesheet logs.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Result timesheetsFilter(Long id) {

        try {

            // get the filter config
            String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());
            FilterConfig<TimesheetLogListView> filterConfig = this.getTableProvider()
                    .get().timesheetLog.filterConfig.persistCurrentInDefault(uid, request());

            if (filterConfig == null) {
                return ok(views.html.framework_views.parts.table.dynamic_tableview_no_more_compatible.render());
            } else {

                // get the table
                Pair<Table<TimesheetLogListView>, Pagination<TimesheetLog>> t = getTimesheetsTable(id,
                        filterConfig);

                return ok(
                        views.html.framework_views.parts.table.dynamic_tableview.render(t.getLeft(), t.getRight()));

            }

        } catch (Exception e) {
            return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                    getI18nMessagesPlugin());
        }
    }

    /**
     * Export the content of the current timesheet logs table as Excel.
     * 
     * @param id
     *            the portfolio entry id
     */
    @With(CheckPortfolioEntryExists.class)
    @Dynamic(IMafConstants.PORTFOLIO_ENTRY_DETAILS_DYNAMIC_PERMISSION)
    public Promise<Result> exportTimesheetsAsExcel(final Long id) {

        return Promise.promise(new Function0<Result>() {
            @Override
            public Result apply() throws Throwable {

                try {

                    // Get the current user
                    final String uid = getUserSessionManagerPlugin().getUserSessionId(ctx());

                    // construct the table
                    FilterConfig<TimesheetLogListView> filterConfig = getTableProvider()
                            .get().timesheetLog.filterConfig.getCurrent(uid, request());

                    ExpressionList<TimesheetLog> expressionList = filterConfig
                            .updateWithSearchExpression(TimesheetDao.getTimesheetLogAsExprByPortfolioEntry(id));
                    filterConfig.updateWithSortExpression(expressionList);

                    List<TimesheetLogListView> timesheetLogListView = new ArrayList<TimesheetLogListView>();
                    for (TimesheetLog timesheetLog : expressionList.findList()) {
                        timesheetLogListView.add(new TimesheetLogListView(timesheetLog));
                    }

                    Table<TimesheetLogListView> table = getTableProvider().get().timesheetLog.templateTable
                            .fillForFilterConfig(timesheetLogListView, filterConfig.getColumnsToHide());

                    final byte[] excelFile = TableExcelRenderer.renderFormatted(table);

                    final String fileName = String
                            .format("timesheetsExport_%1$td_%1$tm_%1$ty_%1$tH-%1$tM-%1$tS.xlsx", new Date());
                    final String successTitle = Msg.get("excel.export.success.title");
                    final String successMessage = Msg.get("excel.export.success.message", fileName);
                    final String failureTitle = Msg.get("excel.export.failure.title");
                    final String failureMessage = Msg.get("excel.export.failure.message");

                    // Execute asynchronously
                    getSysAdminUtils().scheduleOnce(false, "Timesheets Excel Export",
                            Duration.create(0, TimeUnit.MILLISECONDS), new Runnable() {
                                @Override
                                public void run() {

                                    try {
                                        OutputStream out = getPersonalStoragePlugin().createNewFile(uid, fileName);
                                        IOUtils.copy(new ByteArrayInputStream(excelFile), out);
                                        getNotificationManagerPlugin().sendNotification(uid,
                                                NotificationCategory.getByCode(Code.DOCUMENT), successTitle,
                                                successMessage,
                                                controllers.my.routes.MyPersonalStorage.index().url());
                                    } catch (IOException e) {
                                        log.error("Unable to export the excel file", e);
                                        getNotificationManagerPlugin().sendNotification(uid,
                                                NotificationCategory.getByCode(Code.ISSUE), failureTitle,
                                                failureMessage,
                                                controllers.core.routes.PortfolioEntryStatusReportingController
                                                        .timesheets(id).url());
                                    }
                                }
                            });

                    return ok(Json.newObject());

                } catch (Exception e) {
                    return ControllersUtils.logAndReturnUnexpectedError(e, log, getConfiguration(),
                            getI18nMessagesPlugin());
                }
            }
        });

    }

    /**
     * Get the timesheet entries table for a portfolio entry and a filter
     * config.
     * 
     * @param portfolioEntryId
     *            the portfolio entry id
     * @param filterConfig
     *            the filter config.
     */
    private Pair<Table<TimesheetLogListView>, Pagination<TimesheetLog>> getTimesheetsTable(Long portfolioEntryId,
            FilterConfig<TimesheetLogListView> filterConfig) {

        ExpressionList<TimesheetLog> expressionList = filterConfig
                .updateWithSearchExpression(TimesheetDao.getTimesheetLogAsExprByPortfolioEntry(portfolioEntryId));
        filterConfig.updateWithSortExpression(expressionList);

        Pagination<TimesheetLog> pagination = new Pagination<TimesheetLog>(this.getPreferenceManagerPlugin(),
                expressionList);
        pagination.setCurrentPage(filterConfig.getCurrentPage());

        List<TimesheetLogListView> timesheetLogListView = new ArrayList<TimesheetLogListView>();
        for (TimesheetLog timesheetLog : pagination.getListOfObjects()) {
            timesheetLogListView.add(new TimesheetLogListView(timesheetLog));
        }

        Set<String> columnsToHide = filterConfig.getColumnsToHide();
        columnsToHide.add("portfolioEntry");
        columnsToHide.add("timesheetActivity");

        Table<TimesheetLogListView> table = this.getTableProvider().get().timesheetLog.templateTable
                .fillForFilterConfig(timesheetLogListView, columnsToHide);

        return Pair.of(table, pagination);

    }

    /**
     * Get the template name and format for the status report.
     * 
     * It is represented by the standard report in PDF if the corresponding
     * preference is empty, or a custom report else.
     */
    private Pair<String, Format> getReportStatusTemplateNameAndFormat() {
        String customTemplateNameAndFormat = getPreferenceManagerPlugin()
                .getPreferenceValueAsString(IMafConstants.CUSTOM_REPORT_TEMPLATE_FOR_STATUS_REPORT_PREFERENCE);
        if (customTemplateNameAndFormat == null || customTemplateNameAndFormat.equals("")) {
            return Pair.of("status_report", Format.PDF);
        } else {
            String[] tmp = customTemplateNameAndFormat.split(",");
            return Pair.of(tmp[0], Format.valueOf(tmp[1]));
        }
    }

    /**
     * Get the notification manager service.
     */
    private INotificationManagerPlugin getNotificationManagerPlugin() {
        return notificationManagerPlugin;
    }

    /**
     * Get the personal storage service.
     */
    private IPersonalStoragePlugin getPersonalStoragePlugin() {
        return personalStoragePlugin;
    }

    /**
     * Get the user session manager service.
     */
    private IUserSessionManagerPlugin getUserSessionManagerPlugin() {
        return userSessionManagerPlugin;
    }

    /**
     * Get the preference manager service.
     */
    private IPreferenceManagerPlugin getPreferenceManagerPlugin() {
        return preferenceManagerPlugin;
    }

    /**
     * Get the reporting utils.
     */
    private IReportingUtils getReportingUtils() {
        return reportingUtils;
    }

    /**
     * Get the system admin utils.
     */
    private ISysAdminUtils getSysAdminUtils() {
        return sysAdminUtils;
    }

    /**
     * Get the i18n messages service.
     */
    private II18nMessagesPlugin getI18nMessagesPlugin() {
        return i18nMessagesPlugin;
    }

    /**
     * Get the attachment manager service.
     */
    private IAttachmentManagerPlugin getAttachmentManagerPlugin() {
        return attachmentManagerPlugin;
    }

    /**
     * Get the security service.
     */
    private ISecurityService getSecurityService() {
        return securityService;
    }

    /**
     * Get the Play configuration service.
     */
    private Configuration getConfiguration() {
        return configuration;
    }

    /**
     * Get the table provider.
     */
    private ITableProvider getTableProvider() {
        return this.tableProvider;
    }

    /**
     * Get the custom attribute manager service.
     */
    private ICustomAttributeManagerService getCustomAttributeManagerService() {
        return this.customAttributeManagerService;
    }

}