org.projectforge.business.fibu.kost.reporting.Report.java Source code

Java tutorial

Introduction

Here is the source code for org.projectforge.business.fibu.kost.reporting.Report.java

Source

/////////////////////////////////////////////////////////////////////////////
//
// Project ProjectForge Community Edition
//         www.projectforge.org
//
// Copyright (C) 2001-2014 Kai Reinhard (k.reinhard@micromata.de)
//
// ProjectForge is dual-licensed.
//
// This community edition 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 3 of the License.
//
// This community edition 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 org.projectforge.business.fibu.kost.reporting;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ObjectUtils;
import org.projectforge.business.fibu.KostFormatter;
import org.projectforge.business.fibu.kost.AccountingConfig;
import org.projectforge.business.fibu.kost.BuchungssatzDO;
import org.projectforge.business.fibu.kost.BusinessAssessment;
import org.projectforge.business.fibu.kost.BusinessAssessmentTable;
import org.projectforge.framework.persistence.user.api.ThreadLocalUserContext;

/**
 * Ein Report enthlt unterliegende Buchungsstze, die gem Zeitraum und zugehrigem ReportObjective selektiert werden.
 * @author Kai Reinhard (k.reinhard@micromata.de)
 * 
 */
public class Report implements Serializable {
    private static final long serialVersionUID = -5359861335173843043L;

    private transient List<BuchungssatzDO> buchungssaetze;

    private transient Set<BuchungssatzDO> buchungssatzSet;

    private transient ReportObjective reportObjective;

    private transient List<Report> childReports;

    private transient List<BuchungssatzDO> other;

    private transient List<BuchungssatzDO> duplicates;

    private boolean showChilds;

    private transient BusinessAssessment businessAssessment;

    private transient BusinessAssessmentTable businessAssessmentTable;

    private int fromYear;

    private int fromMonth;

    private int toYear;

    private int toMonth;

    private transient Report parent;

    public Report(final ReportObjective reportObjective) {
        this.reportObjective = reportObjective;
    }

    public Report(final ReportObjective reportObjective, final Report parent) {
        this(reportObjective, parent.fromYear, parent.fromMonth, parent.toYear, parent.toMonth);
        this.parent = parent;
    }

    public Report(final ReportObjective reportObjective, final int fromYear, final int fromMonth, final int toYear,
            final int toMonth) {
        this(reportObjective);
        this.fromYear = fromYear;
        this.fromMonth = fromMonth;
        this.toYear = toYear;
        this.toMonth = toMonth;
    }

    public void setFrom(final int year, final int month) {
        this.fromYear = year;
        this.fromMonth = month;
    }

    public void setTo(final int year, final int month) {
        this.toYear = year;
        this.toMonth = month;
    }

    public int getFromYear() {
        return fromYear;
    }

    public int getFromMonth() {
        return fromMonth;
    }

    public int getToYear() {
        return toYear;
    }

    public int getToMonth() {
        return toMonth;
    }

    public Report getParent() {
        return parent;
    }

    /**
     * Gibt den Reportpfad zurck, vom Root-Report bis zum direkten Eltern-Report. Der Report selber ist nicht im Pfad enthalten.
     * @return Liste oder null, wenn der Report keinen Elternreport hat.
     */
    public List<Report> getPath() {
        if (this.parent == null) {
            return null;
        }
        final List<Report> path = new ArrayList<Report>();
        this.parent.getPath(path);
        return path;
    }

    private void getPath(final List<Report> path) {
        if (this.parent != null) {
            this.parent.getPath(path);
        }
        path.add(this);
    }

    public ReportObjective getReportObjective() {
        return reportObjective;
    }

    public BusinessAssessment getBusinessAssessment() {
        if (this.businessAssessment == null) {
            this.businessAssessment = new BusinessAssessment(
                    AccountingConfig.getInstance().getBusinessAssessmentConfig());
            this.businessAssessment.setReference(this);
            this.businessAssessment.setStoreAccountRecordsInRows(true);
            this.businessAssessment.setAccountRecords(this.buchungssaetze);
        }
        return this.businessAssessment;
    }

    /**
     * Creates an array with all business assessment's of the child reports.
     * @param prependThisReport If true then the business assessment of this report will be prepend as first column.
     */
    public BusinessAssessmentTable getChildBusinessAssessmentTable(final boolean prependThisReport) {
        if (businessAssessmentTable == null) {
            if (prependThisReport == false && hasChilds() == false) {
                return null;
            }
            businessAssessmentTable = new BusinessAssessmentTable();
            if (prependThisReport == true) {
                businessAssessmentTable.addBusinessAssessment(this.getId(), this.getBusinessAssessment());
            }
            if (hasChilds() == true) {
                for (final Report child : getChilds()) {
                    businessAssessmentTable.addBusinessAssessment(child.getId(), child.getBusinessAssessment());
                }
            }
        }
        return businessAssessmentTable;
    }

    /**
     * Wurde eine Selektion bereits durchgefhrt?
     * @return true, wenn Buchungsstzeliste vorhanden ist (kann aber auf Grund der Selektion auch leer sein).
     */
    public boolean isLoad() {
        return this.buchungssaetze != null;
    }

    public boolean isShowChilds() {
        return showChilds;
    }

    public void setShowChilds(final boolean showChilds) {
        this.showChilds = showChilds;
    }

    /**
     * @see ReportObjective#hasChilds()
     */
    public boolean hasChilds() {
        return reportObjective.getHasChilds();
    }

    /**
     * @see ReportObjective#getId()
     */
    public String getId() {
        return reportObjective.getId();
    }

    /**
     * @see ReportObjective#getTitle()
     */
    public String getTitle() {
        return reportObjective.getTitle();
    }

    public Report findById(final String id) {
        if (ObjectUtils.equals(this.reportObjective.getId(), id) == true) {
            return this;
        }
        if (hasChilds() == false) {
            return null;
        }
        for (final Report report : getChilds()) {
            if (ObjectUtils.equals(report.reportObjective.getId(), id) == true) {
                return report;
            }
        }
        for (final Report report : getChilds()) {
            final Report result = report.findById(id);
            if (result != null) {
                return result;
            }
        }
        return null;
    }

    /**
     * Creates and get the childs if the ReportObjective has childs. Iteriert ber alle ChildReportObjectives und legt jeweils einen Report an
     * und selektiert gem Filter des ReportObjectives die Buchungsstze. Wenn Childs nicht implizit erzeugt werden sollen, so sollte die
     * Funktion hasChilds zur Abfrage genutzt werden.
     * @see #select(List)
     */
    public List<Report> getChilds() {
        if (childReports == null && hasChilds() == true) {
            childReports = new ArrayList<Report>();
            for (final ReportObjective child : reportObjective.getChildReportObjectives()) {
                final Report report = new Report(child, this);
                report.select(this.buchungssaetze);
                childReports.add(report);
            }
            if (this.buchungssaetze != null && (reportObjective.isSuppressOther() == false
                    || reportObjective.isSuppressDuplicates() == false)) {
                for (final BuchungssatzDO satz : this.buchungssaetze) {
                    int n = 0;
                    for (final Report child : getChilds()) {
                        if (child.contains(satz) == true) {
                            n++;
                        }
                    }
                    if (reportObjective.isSuppressOther() == false && n == 0) {
                        // Kommt bei keinem Childreport vor:
                        if (other == null) {
                            other = new ArrayList<BuchungssatzDO>();
                        }
                        other.add(satz);
                    } else if (reportObjective.isSuppressDuplicates() == false && n > 1) {
                        // Kommt bei mehreren Childs vor:
                        if (duplicates == null) {
                            duplicates = new ArrayList<BuchungssatzDO>();
                        }
                        duplicates.add(satz);
                    }
                }
            }
            if (reportObjective.isSuppressOther() == false && this.other != null) {
                final ReportObjective objective = new ReportObjective();
                final String other = ThreadLocalUserContext.getLocalizedString("fibu.reporting.other");
                objective.setId(this.getId() + " - " + other);
                objective.setTitle(this.getTitle() + " - " + other);
                final Report report = new Report(objective, this);
                report.setBuchungssaetze(this.other);
                childReports.add(report);
            }
            if (reportObjective.isSuppressDuplicates() == false && this.duplicates != null) {
                final ReportObjective objective = new ReportObjective();
                final String duplicates = ThreadLocalUserContext.getLocalizedString("fibu.reporting.duplicates");
                objective.setId(this.getId() + " - " + duplicates);
                objective.setTitle(this.getTitle() + " - " + duplicates);
                final Report report = new Report(objective, this);
                report.setBuchungssaetze(this.duplicates);
                childReports.add(report);
            }
        }
        return childReports;
    }

    public List<BuchungssatzDO> getBuchungssaetze() {
        return buchungssaetze;
    }

    /**
     * Bitte entweder diese Methode ODER select(...) benutzen.
     * @param buchungssaetze
     */
    public void setBuchungssaetze(final List<BuchungssatzDO> buchungssaetze) {
        this.buchungssaetze = buchungssaetze;
    }

    /**
     * Gibt die Liste aller sonstigen Buchungsstze zurck, d. h. Buchungsstze, die zwar in diesem Report vorkommen aber in keinem der
     * Childreports vorkommen.
     * @return Liste oder null, wenn keine Eintrge vorhanden sind.
     */
    public List<BuchungssatzDO> getOther() {
        return other;
    }

    /**
     * Gibt die Liste aller doppelten Buchungsstze zurck, d. h. Buchungsstze, die in mehreren Childreports vorkommen.
     * @return Liste oder null, wenn keine Eintrge vorhanden sind.
     */
    public List<BuchungssatzDO> getDuplicates() {
        return duplicates;
    }

    public String getZeitraum() {
        return KostFormatter.formatZeitraum(fromYear, fromMonth, toYear, toMonth);
    }

    /**
     * Diese initiale Liste der Buchungsliste wird sofort bezglich Exclude- und Include-Filter selektiert und das Ergebnis gesetzt.
     * @param buchungssaetze vor Selektion.
     */
    public void select(final List<BuchungssatzDO> list) {
        final Predicate regExpPredicate = new Predicate() {
            public boolean evaluate(final Object obj) {
                final BuchungssatzDO satz = (BuchungssatzDO) obj;
                final String kost1 = KostFormatter.format(satz.getKost1());
                final String kost2 = KostFormatter.format(satz.getKost2());

                // 1st of all the Blacklists
                if (match(reportObjective.getKost1ExcludeRegExpList(), kost1, false) == true) {
                    return false;
                }
                if (match(reportObjective.getKost2ExcludeRegExpList(), kost2, false) == true) {
                    return false;
                }
                // 2nd the whitelists
                final boolean kost1Match = match(reportObjective.getKost1IncludeRegExpList(), kost1, true);
                final boolean kost2Match = match(reportObjective.getKost2IncludeRegExpList(), kost2, true);
                return kost1Match == true && kost2Match == true;
            }
        };
        this.buchungssaetze = new ArrayList<BuchungssatzDO>();
        this.buchungssatzSet = new HashSet<BuchungssatzDO>();
        this.businessAssessment = null;
        this.businessAssessmentTable = null;
        this.childReports = null;
        this.duplicates = null;
        this.other = null;
        CollectionUtils.select(list, regExpPredicate, this.buchungssaetze);
        for (final BuchungssatzDO satz : this.buchungssaetze) {
            this.buchungssatzSet.add(satz);
        }
    }

    public boolean contains(final BuchungssatzDO satz) {
        if (buchungssatzSet == null) {
            return false;
        }
        return this.buchungssatzSet.contains(satz);
    }

    /**
     * In jedem regulrem Ausdruck werden alle Punkte gequoted und alle * durch ".*" ersetzt, bevor der Ausdruck durch
     * {@link Pattern#compile(String)} kompiliert wird.<br/>
     * Beispiele:
     * <ul>
     * <li>5.100.* -&gt; 5\.100\..*</li>
     * <li>*.10.* -&gt; .*\.10\..*</li>
     * </ul>
     * @param regExpList
     * @param kost
     * @param emptyListMatches
     * @return
     * @see String#matches(String)()
     * @see #modifyRegExp(String)
     */
    public static boolean match(final List<String> regExpList, final String kost, final boolean emptyListMatches) {
        if (CollectionUtils.isNotEmpty(regExpList) == true) {
            for (final String str : regExpList) {
                final String regExp = modifyRegExp(str);
                if (kost.matches(regExp) == true) {
                    return true;
                }
            }
            return false;
        } else {
            // List is empty:
            return emptyListMatches;
        }
    }

    /**
     * Alle Punkte werden gequoted und alle * durch ".*" ersetzt. Ausnahme: Der String beginnt mit einem einfachen Hochkomma, dann werden
     * keine Ersetzungen durchgefhrt, sondern lediglich das Hochkomma selbst entfernt.
     * @param regExp
     */
    public static String modifyRegExp(final String regExp) {
        if (regExp == null) {
            return null;
        }
        if (regExp.startsWith("'") == true) {
            return regExp.substring(1);
        }
        final String str = regExp.replace(".", "\\.").replace("*", ".*");
        return str;
    }
}