/* This file is part of Cyclos (www.cyclos.org). A project of the Social Trade Organisation (www.socialtrade.org). Cyclos 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; either version 2 of the License, or (at your option) any later version. Cyclos 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 Cyclos; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package nl.strohalm.cyclos.services.stats; import java.util.Collection; import nl.strohalm.cyclos.entities.accounts.Currency; import nl.strohalm.cyclos.entities.accounts.SystemAccountType; import nl.strohalm.cyclos.entities.accounts.transactions.PaymentFilter; import nl.strohalm.cyclos.entities.reports.StatisticalFinancesQuery; import nl.strohalm.cyclos.entities.reports.StatisticalQuery; import nl.strohalm.cyclos.services.stats.finances.FinanceStatsComparePeriods; import nl.strohalm.cyclos.services.stats.finances.FinanceStatsSinglePeriod; import nl.strohalm.cyclos.services.stats.finances.FinanceStatsThroughTime; import nl.strohalm.cyclos.utils.NamedPeriod; import nl.strohalm.cyclos.utils.Period; /** * implementation of the StatisticalFinancesService.<br> * This class is responsible of the gathering of the Finance Statistics. The calculations are delegated to the {@link FinanceStatsSinglePeriod} class. * * @author Rinke * */ public class StatisticalFinancesServiceImpl extends StatisticalServiceImpl implements StatisticalFinancesServiceLocal { public StatisticalResultDTO getComparePeriodsExpenditure(final StatisticalFinancesQuery queryParameters) { final FinanceStatsComparePeriods compareStats = getCompareStats(); final NamedPeriod periodMain = queryParameters.getPeriodMain(); final NamedPeriod periodAlt = queryParameters.getPeriodComparedTo(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.ComparePeriods.expenditure"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = compareStats.getTableCellsExpenditureComparePeriods(periodMain, periodAlt, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); applyColumnHeadersAndKeys(result, queryParameters); assignRowKeysCompare(result, paymentFilters); // filter assignment passSystemAccountFilter(result, queryParameters); applyCurrency(result, queryParameters, 3, 2); // rendering of graph or table if (queryParameters.isExpenditureGraph()) { result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 2); result.setGraphType(StatisticalResultDTO.GraphType.BAR); } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } public StatisticalResultDTO getComparePeriodsIncome(final StatisticalFinancesQuery queryParameters) { final FinanceStatsComparePeriods compareStats = getCompareStats(); final NamedPeriod periodMain = queryParameters.getPeriodMain(); final NamedPeriod periodAlt = queryParameters.getPeriodComparedTo(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.ComparePeriods.income"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = compareStats.getTableCellsIncomeComparePeriods(periodMain, periodAlt, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); applyColumnHeadersAndKeys(result, queryParameters); assignRowKeysCompare(result, paymentFilters); // filter assignment passSystemAccountFilter(result, queryParameters); applyCurrency(result, queryParameters, 3, 2); // rendering of graph or table if (queryParameters.isIncomeGraph()) { result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 2); result.setGraphType(StatisticalResultDTO.GraphType.BAR); } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } public StatisticalResultDTO getSinglePeriodExpenditure(final StatisticalFinancesQuery queryParameters) { final FinanceStatsSinglePeriod singlePeriodStats = getFinanceStats(); final NamedPeriod period = queryParameters.getPeriodMain(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.singlePeriod.expenditure"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = singlePeriodStats.getTableCellsExpenditureSinglePeriod(period, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); final String[] colKeys = { "reports.stats.finances.expenditure" }; result.setColumnKeys(colKeys); assignRowKeysSingle(result, paymentFilters, tableCells.length); // filter assignment passSystemAccountFilter(result, queryParameters); passPaymentFilter(result, queryParameters); result.setFilter(period); applyCurrency(result, queryParameters, 1, 1); // rendering of graph or table if (queryParameters.isOverview()) { result.setShowTable(false); result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 1); result.setGraphType(StatisticalResultDTO.GraphType.PIE); } else { if (queryParameters.isIncomeGraph()) { result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 1); result.setGraphType(StatisticalResultDTO.GraphType.PIE); } } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } /** * gets the results for single period income. */ public StatisticalResultDTO getSinglePeriodIncome(final StatisticalFinancesQuery queryParameters) { final FinanceStatsSinglePeriod singlePeriodStats = getFinanceStats(); final NamedPeriod period = queryParameters.getPeriodMain(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.singlePeriod.income"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = singlePeriodStats.getTableCellsIncomeSinglePeriod(period, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); final String[] colKeys = { "reports.stats.finances.income" }; result.setColumnKeys(colKeys); assignRowKeysSingle(result, paymentFilters, tableCells.length); // filter assignment passSystemAccountFilter(result, queryParameters); passPaymentFilter(result, queryParameters); result.setFilter(period); applyCurrency(result, queryParameters, 1, 1); // rendering of graph or table if (queryParameters.isOverview()) { result.setShowTable(false); result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 1); result.setGraphType(StatisticalResultDTO.GraphType.PIE); } else { if (queryParameters.isIncomeGraph()) { result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, null, 1); result.setGraphType(StatisticalResultDTO.GraphType.PIE); } } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } /** * gathers the results for the single period overview, and stores this in the <code>StatisticalResultDTO</code>. */ public StatisticalResultDTO getSinglePeriodOverview(final StatisticalFinancesQuery queryParameters) { final FinanceStatsSinglePeriod singlePeriodStats = getFinanceStats(); final NamedPeriod period = queryParameters.getPeriodMain(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.singlePeriod.overview"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = singlePeriodStats.getTableCellsOverviewSinglePeriod(period, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); final String[] colKeys = { "reports.stats.finances.income", "reports.stats.finances.expenditure", "reports.stats.finances.balance" }; result.setColumnKeys(colKeys); assignRowKeysSingle(result, paymentFilters, tableCells.length); // filter assignment passSystemAccountFilter(result, queryParameters); passPaymentFilter(result, queryParameters); result.setFilter(period); applyCurrency(result, queryParameters, 3, 3); // graph if (queryParameters.isOverviewGraph()) { result.setGraphDimensions(StatisticalResultDTO.TableToGraph.COLUMN_IS_CATEGORY, tableCells.length - 2, 2); result.setGraphType(StatisticalResultDTO.GraphType.BAR); } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } public StatisticalResultDTO getThroughTimeExpenditure(final StatisticalFinancesQuery queryParameters) { final FinanceStatsThroughTime thruStats = getThruStats(); final Period[] periods = queryParameters.getPeriods(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.ThroughTime.expenditure"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = thruStats.getTableCellsExpenditureThroughTime(periods, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); applyColumnHeadersAndKeys(result, paymentFilters); assignRowHeaders(result, queryParameters, periods); // filter assignment passSystemAccountFilter(result, queryParameters); applyCurrency(result, queryParameters, paymentFilters.size(), paymentFilters.size()); // rendering of graph or table if (queryParameters.isExpenditureGraph()) { result.setGraphType(StatisticalResultDTO.GraphType.LINE); } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } public StatisticalResultDTO getThroughTimeIncome(final StatisticalFinancesQuery queryParameters) { final FinanceStatsThroughTime thruStats = getThruStats(); final Period[] periods = queryParameters.getPeriods(); final Collection<PaymentFilter> paymentFilters = getInitializedPaymentFilters(queryParameters); final SystemAccountType systemAccountFilter = getInitializedSystemAccountFilter(queryParameters); // Initialize StatisticalResultDTO result = null; final String baseKey = "reports.stats.finances.ThroughTime.income"; // Assignment of results if (paymentFilters.size() > 0) { final Number[][] tableCells = thruStats.getTableCellsIncomeThroughTime(periods, paymentFilters, systemAccountFilter); result = new StatisticalResultDTO(tableCells); result.setBaseKey(baseKey); applyColumnHeadersAndKeys(result, paymentFilters); assignRowHeaders(result, queryParameters, periods); // filter assignment passSystemAccountFilter(result, queryParameters); applyCurrency(result, queryParameters, paymentFilters.size(), paymentFilters.size()); // rendering of graph or table if (queryParameters.isIncomeGraph()) { result.setGraphType(StatisticalResultDTO.GraphType.LINE); } } else { result = StatisticalResultDTO.noDataAvailable(baseKey); } return result; } /** * Creates the column headers and keys from the query for through time. * * @param result the raw data object * @param queryParameters */ private void applyColumnHeadersAndKeys(final StatisticalResultDTO result, final Collection<PaymentFilter> paymentFilters) { final String[] columnKeys = new String[paymentFilters.size()]; result.setColumnKeys(columnKeys); int i = 0; for (final PaymentFilter paymentFilter : paymentFilters) { result.setColumnHeader(paymentFilter.getName(), i++); } } /** * Creates the column headers and keys from the query for Compare periods. This is (usually) namePeriod1, namePeriod2 and "Growth". Beware that it * also sets the columnSubHeaders. If you reset this, the third column subHeader will be overwritten. * @param result the raw data object * @param queryParameters */ private void applyColumnHeadersAndKeys(final StatisticalResultDTO result, final StatisticalQuery queryParameters) { final String[] columnKeys = { "", "", "reports.stats.general.growth" }; result.setColumnKeys(columnKeys); result.setColumnHeader(queryParameters.getPeriodMain().getName(), 1); result.setColumnHeader(queryParameters.getPeriodComparedTo().getName(), 0); } /** * Takes care that the units of the currency are placed in the Column subHeader, between perenthesis. Also passes the units to the y-axis label of * the graph. * * @param result the <code>StatisticalResultDTO</code> result object to which all must be passed to. * @param queryParameters the <code>StatisticalQuery</code> object containing the form params * @param totalCols an int specifying the total amount of column headers. * @param applyToCols an int specifying the number of column subheaders in which the units of the currency must be placed. If this equals * totalCols, all columns get this subHeader. SubHeaders are assigned starting from index 0, so if this equals totalCols - 1, only the last column * gets NO subHeader. * @throws IllegalArgumentException if applyToCols > totalCols */ private void applyCurrency(final StatisticalResultDTO result, final StatisticalQuery queryParameters, final int totalCols, final int applyToCols) { if (applyToCols > totalCols) { throw new IllegalArgumentException("Too many column subHeaders specified"); } final Currency currency = getCurrency(queryParameters); final String[] columnSubHeaders = new String[totalCols]; for (int i = 0; i < totalCols; i++) { columnSubHeaders[i] = (i < applyToCols) ? parenthesizeString(currency.getSymbol()) : ""; } result.setColumnSubHeaders(columnSubHeaders); result.setYAxisUnits(currency.getSymbol()); } /** * assigns row headers for through time * @param result * @param queryParameters * @param periods */ private void assignRowHeaders(final StatisticalResultDTO result, final StatisticalQuery queryParameters, final Period[] periods) { final String[] rowHeaders = new String[periods.length]; int i = 0; for (final Period period : periods) { rowHeaders[i++] = getRowHeaders(queryParameters.getThroughTimeRange(), period); } result.setRowHeaders(rowHeaders); } /** * assigns row keys to the result object, for all compare periods cases. * * @param result the <code>StatisticalResultDTO</code> object * @param paymentFilters the names of these paymentfilters will simply be added. */ private void assignRowKeysCompare(final StatisticalResultDTO result, final Collection<PaymentFilter> paymentFilters) { final String[] rowHeaders = new String[paymentFilters.size()]; int i = 0; for (final PaymentFilter filter : paymentFilters) { rowHeaders[i++] = filter.getName(); } result.setRowHeaders(rowHeaders); } /** * assigns the rowKeys for all Single period cases. * * @param result the <code>StatisticalResultDTO</code> object * @param paymentFilters * @param length the total number of needed row keys. If bigger than the size of the paymentFilters collection, than "other" and "sum" may be * added to the rowkeys. */ private void assignRowKeysSingle(final StatisticalResultDTO result, final Collection<PaymentFilter> paymentFilters, final int length) { final String[] filterNames = getFinanceStats().getPaymentFilterNames(paymentFilters); final String[] rowKeys = new String[length]; final int extraKeysCount = length - filterNames.length; if (extraKeysCount == 2) { rowKeys[length - 2] = "reports.stats.finances.other"; rowKeys[length - 1] = "reports.stats.general.sum"; } if (extraKeysCount == 1) { rowKeys[length - 1] = "reports.stats.finances.other"; } result.setRowKeys(rowKeys); for (int i = 0; i < filterNames.length; i++) { result.setRowHeader(filterNames[i], i); } } private FinanceStatsComparePeriods getCompareStats() { return new FinanceStatsComparePeriods(getTransferDao()); } private FinanceStatsSinglePeriod getFinanceStats() { return new FinanceStatsSinglePeriod(getTransferDao()); } private FinanceStatsThroughTime getThruStats() { return new FinanceStatsThroughTime(getTransferDao()); } }