/* * Copyright (c) 2011 Denis Solonenko. * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Public License v2.0 * which accompanies this distribution, and is available at * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html */ package ru.orangesoftware.financisto2.test.db; import android.database.Cursor; import java.util.Map; import ru.orangesoftware.financisto2.blotter.BlotterFilter; import ru.orangesoftware.financisto2.db.DatabaseHelper; import ru.orangesoftware.financisto2.db.TransactionsTotalCalculator; import ru.orangesoftware.financisto2.filter.Criteria; import ru.orangesoftware.financisto2.filter.WhereFilter; import ru.orangesoftware.financisto2.model.Account; import ru.orangesoftware.financisto2.model.Category; import ru.orangesoftware.financisto2.model.Total; import ru.orangesoftware.financisto2.test.builders.AccountBuilder; import ru.orangesoftware.financisto2.test.builders.CategoryBuilder; import ru.orangesoftware.financisto2.test.builders.DateTime; import ru.orangesoftware.financisto2.test.builders.TransactionBuilder; import ru.orangesoftware.financisto2.test.builders.TransferBuilder; import static ru.orangesoftware.financisto2.db.DatabaseAdapter.enhanceFilterForAccountBlotter; import static ru.orangesoftware.financisto2.test.builders.DateTime.date; public class AccountBlotterTest extends AbstractDbTest { Account a1; Account a2; Map<String, Category> categoriesMap; @Override public void setUp() throws Exception { super.setUp(); a1 = AccountBuilder.createDefault(db); a2 = AccountBuilder.createDefault(db); categoriesMap = CategoryBuilder.createDefaultHierarchy(categoryRepository); } public void test_should_include_transfer_splits_into_blotter_for_account() { // regular transactions and transfers TransactionBuilder.withDb(db).dateTime(date(2012, 2, 8)).account(a1).amount(1000).create(); TransactionBuilder.withDb(db).dateTime(date(2012, 2, 8)).account(a2).amount(200).create(); assertAccountBlotter(a1, 1000); assertAccountBlotter(a2, 200); assertAccountBlotterTotal(a1, date(2012, 2, 1), date(2012, 2, 7), 0); assertAccountBlotterTotal(a1, date(2012, 2, 1), date(2012, 2, 8), 1000); assertAccountBlotterTotal(a2, date(2012, 2, 8), date(2012, 2, 9), 200); // regular transfer TransferBuilder.withDb(db).dateTime(date(2012, 2, 9)).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(50).create(); assertAccountBlotter(a1, -100, 1000); assertAccountBlotter(a2, 50, 200); assertAccountBlotterTotal(a1, date(2012, 2, 1), date(2012, 2, 9), 900); assertAccountBlotterTotal(a2, date(2012, 2, 8), date(2012, 2, 9), 250); // regular split TransactionBuilder.withDb(db).dateTime(date(2012, 2, 10)).account(a1).amount(-500) .withSplit(categoriesMap.get("A1"), -200) .withSplit(categoriesMap.get("A1"), -300) .create(); assertAccountBlotter(a1, -500, -100, 1000); assertAccountBlotter(a2, 50, 200); assertAccountBlotterTotal(a1, date(2012, 2, 1), date(2012, 2, 10), 400); assertAccountBlotterTotal(a1, date(2012, 2, 9), date(2012, 2, 10), -600); assertAccountBlotterTotal(a2, date(2012, 2, 1), date(2012, 2, 9), 250); // transfer split TransactionBuilder.withDb(db).dateTime(date(2012, 2, 11)).account(a2).amount(-120) .withSplit(categoriesMap.get("B"), -20) .withTransferSplit(a1, -100, 200) .create(); assertAccountBlotter(a1, 200, -500, -100, 1000); assertAccountBlotter(a2, -120, 50, 200); assertAccountBlotterTotal(a1, date(2012, 2, 1), date(2012, 2, 12), 600); assertAccountBlotterTotal(a2, date(2012, 2, 1), date(2012, 2, 12), 130); } public void test_should_verify_running_balance_on_blotter_for_account() { // regular transactions and transfers TransactionBuilder.withDb(db).account(a1).amount(1000).create(); TransactionBuilder.withDb(db).account(a2).amount(200).create(); assertRunningBalance(a1, 1000); assertRunningBalance(a2, 200); assertTotals(1000, 200); // regular transfer TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(50).create(); assertRunningBalance(a1, 900, 1000); assertRunningBalance(a2, 250, 200); assertTotals(900, 250); // regular split TransactionBuilder.withDb(db).account(a1).amount(-500) .withSplit(categoriesMap.get("A1"), -200) .withSplit(categoriesMap.get("A1"), -300) .create(); assertRunningBalance(a1, 400, 900, 1000); assertRunningBalance(a2, 250, 200); assertTotals(400, 250); // transfer split TransactionBuilder.withDb(db).account(a2).amount(-120) .withSplit(categoriesMap.get("B"), -20) .withTransferSplit(a1, -100, 200) .create(); assertRunningBalance(a1, 600, 400, 900, 1000); assertRunningBalance(a2, 130, 250, 200); assertTotals(600, 130); } private void assertAccountBlotter(Account account, long...amounts) { assertAccountBlotterColumn(account, DatabaseHelper.BlotterColumns.from_amount, amounts); } private void assertRunningBalance(Account account, long...amounts) { assertAccountBlotterColumn(account, DatabaseHelper.BlotterColumns.from_account_balance, amounts); } // blotter is from newest to oldest private void assertAccountBlotterColumn(Account account, DatabaseHelper.BlotterColumns column, long...values) { WhereFilter filter = createBlotterForAccountFilter(account); Cursor c = db.getBlotterForAccount(filter); try { int i = 0; while (c.moveToNext()) { if (i >= values.length) { fail("Too many rows "+c.getCount()+". Expected "+values.length); } long expectedAmount = values[i++]; long amount = c.getLong(column.ordinal()); assertEquals("Blotter row "+i, expectedAmount, amount); } if (i != values.length) { fail("Too few rows "+c.getCount()+". Expected "+values.length); } } finally { c.close(); } } private WhereFilter createBlotterForAccountFilter(Account account) { WhereFilter filter = WhereFilter.empty(); filter.put(Criteria.eq(BlotterFilter.FROM_ACCOUNT_ID, String.valueOf(account.id))); return filter; } private void assertAccountBlotterTotal(Account a1, DateTime start, DateTime end, int total) { WhereFilter filter = enhanceFilterForAccountBlotter(WhereFilter.empty()); filter.btw(BlotterFilter.DATETIME, String.valueOf(start.atMidnight().asLong()), String.valueOf(end.atDayEnd().asLong())); filter.eq(BlotterFilter.FROM_ACCOUNT_ID, String.valueOf(a1.id)); TransactionsTotalCalculator calculator = new TransactionsTotalCalculator(db, filter); assertEquals(total, calculator.getAccountTotal().balance); } private void assertTotals(long...totalAmounts) { WhereFilter filter = WhereFilter.empty(); TransactionsTotalCalculator calculator = new TransactionsTotalCalculator(db, filter); Total[] totals = calculator.getTransactionsBalance(); assertEquals(totalAmounts.length, totals.length); for (int i=0; i<totalAmounts.length; i++) { assertEquals("Total "+i, totalAmounts[i], totals[i].balance); } } }