// BudgetReport package org.javamoney.examples.ez.money.report; import static org.javamoney.examples.ez.money.ApplicationProperties.UI_CURRENCY_SYMBOL; import static org.javamoney.examples.ez.common.utility.DateHelper.getMonthSpan; import static org.javamoney.examples.ez.money.model.DataManager.getAccounts; import static org.javamoney.examples.ez.money.model.DataManager.getExpenses; import static org.javamoney.examples.ez.money.model.DataManager.getIncome; import static org.javamoney.examples.ez.money.utility.TransactionDateHelper.isInRange; import static org.javamoney.examples.ez.money.utility.TransactionDateHelper.isOnOrAfter; import static org.javamoney.examples.ez.money.utility.TransactionHelper.isSplit; import static org.javamoney.examples.ez.money.utility.TransactionHelper.isTransfer; import java.util.Collection; import java.util.Date; import java.util.LinkedList; import org.javamoney.examples.ez.money.model.DataElement; import org.javamoney.examples.ez.money.model.dynamic.total.Budget; import org.javamoney.examples.ez.money.model.dynamic.total.CategoryTotalTypeKeys; import org.javamoney.examples.ez.money.model.dynamic.total.TotalFilter; import org.javamoney.examples.ez.money.model.dynamic.total.TransactionDetail; import org.javamoney.examples.ez.money.model.dynamic.transaction.Split; import org.javamoney.examples.ez.money.model.persisted.account.Account; import org.javamoney.examples.ez.money.model.persisted.category.Category; import org.javamoney.examples.ez.money.model.persisted.transaction.Transaction; import org.javamoney.moneta.Money; /** * This class facilitates maintaining data pertaining to a budget report. */ public final class BudgetReport extends Report { /** * This method creates a budget report according to the specified criteria. * * @param start * The report's start date. * @param end * The report's end date. * @param filter * The filter to use. * * @return A budget report. */ public static BudgetReport createReport(Date start, Date end, TotalFilter filter) { BudgetReport report = new BudgetReport(); // Initialize budget. report.setBalanceTotal(0.0); report.setBudgets(new LinkedList<Budget>()); report.setBudgetTotal(0); report.setChangeTotal(0.0); report.setEndDate(end); report.setFilter(filter); report.setRolloverTotal(0.0); report.setStartDate(start); report.addBudgets(); // Iterate all accounts and their transactions. for (DataElement element : getAccounts().getCollection()) { Account account = (Account) element; if (filter.allowsAccount(account) == false) { continue; } for (Transaction trans : account.getTransactions()) { if (isTransfer(trans) == false) { if (filter.allowsPayee(trans) == true && filter.allowsReconciledStatus(trans) == true) { if (isSplit(trans) == true) { report.addSplit(account, trans); } else { report.addCategory(account, trans); } } } } } report.calculateTotals(); return report; } /** * This method returns the report's balance total. * * @return The balance total. */ public double getBalanceTotal() { return itsBalanceTotal; } /** * This method returns the collection of budgets the report pertains to. * * @return The collection of budgets the report pertains to. */ public Collection<Budget> getBudgets() { return itsBudgets; } /** * This method returns the report's budget total. * * @return The budget total. */ public int getBudgetTotal() { return itsBudgetTotal; } /** * This method returns the report's change total. * * @return The change total. */ public double getChangeTotal() { return itsChangeTotal; } /** * This method returns the report's rollover total. * * @return The rollover total. */ public double getRolloverTotal() { return itsRolloverTotal; } // //////////////////////////////////////////////////////////////////////////// // Start of private methods. // //////////////////////////////////////////////////////////////////////////// private void addBudgets() { // Add all budgeted categories. for (DataElement element : getExpenses().getCollection()) { Category category = (Category) element; if (category.isBudgeted() == true) { getBudgets().add( new Budget(CategoryTotalTypeKeys.EXPENSE, category)); } } // Add all budgeted income. for (DataElement element : getIncome().getCollection()) { Category category = (Category) element; if (category.isBudgeted() == true) { getBudgets().add( new Budget(CategoryTotalTypeKeys.INCOME, category)); } } } private void addCategory(Account account, Transaction trans) { Budget budget = getBudgetAt(trans.getCategory()); if (budget != null) { if (getFilter().allowsCategory(trans) == true) { if (isInRange(trans, getStartDate(), getEndDate()) == true) { TransactionDetail detail = new TransactionDetail(trans, account); budget.setChange(budget.getChange() + Math.abs(trans.getAmount().getNumber() .doubleValue())); budget.getTransactionDetails().add(detail); } else if (budget.hasRolloverBalance() == true) { if (trans.getDate().before(getStartDate()) == true) { if (isOnOrAfter(trans, budget.getRolloverStartDate()) == true) { budget.setStartingBalance(budget .getStartingBalance() + trans.getAmount().getNumber() .doubleValue()); } } } } } } private void addSplit(Account account, Transaction trans) { Split split = new Split(trans); for (int index = 0; index < split.size(); ++index) { trans = trans.clone(); trans.setAmount(Money.of(split.getAmount(index), UI_CURRENCY_SYMBOL.getCurrency())); trans.setCategory(split.getCategory(index)); addCategory(account, trans); } } private void calculateTotals() { int monthSpan = 1 + getMonthSpan(getStartDate(), getEndDate()); for (Budget budget : getBudgets()) { // Set the proper starting balance. if (budget.hasRolloverBalance() == true) { int startSpan = getMonthSpan(budget.getRolloverStartDate(), getStartDate()); double startingBalance = budget.getAmount() * startSpan; budget.setStartingBalance(budget.getStartingBalance() + startingBalance); } // Set span so budget properly computes its data. budget.setMonthSpan(monthSpan); setBalanceTotal(getBalanceTotal() + budget.getBalance()); setBudgetTotal(getBudgetTotal() + budget.getBudget()); setChangeTotal(getChangeTotal() + budget.getChange()); setRolloverTotal(getRolloverTotal() + budget.getStartingBalance()); } } private Budget getBudgetAt(String category) { Budget budgetAt = null; for (Budget budget : getBudgets()) { if (budget.isBudgetFor(category) == true) { budgetAt = budget; break; } } return budgetAt; } private void setBalanceTotal(double amount) { itsBalanceTotal = amount; } private void setBudgets(Collection<Budget> collection) { itsBudgets = collection; } private void setBudgetTotal(int amount) { itsBudgetTotal = amount; } private void setChangeTotal(double amount) { itsChangeTotal = amount; } private void setRolloverTotal(double amount) { itsRolloverTotal = amount; } // //////////////////////////////////////////////////////////////////////////// // Start of class members. // //////////////////////////////////////////////////////////////////////////// private double itsBalanceTotal; private Collection<Budget> itsBudgets; private int itsBudgetTotal; private double itsChangeTotal; private double itsRolloverTotal; }