/*
* 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 java.util.List;
import java.util.Map;
import ru.orangesoftware.financisto2.model.Account;
import ru.orangesoftware.financisto2.model.Category;
import ru.orangesoftware.financisto2.model.Transaction;
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;
public class RunningBalanceTest extends AbstractDbTest {
Account a1;
Account a2;
Account a3;
Map<String, Category> categoriesMap;
@Override
public void setUp() throws Exception {
super.setUp();
a1 = AccountBuilder.createDefault(db);
a2 = AccountBuilder.createDefault(db);
a3 = AccountBuilder.createDefault(db);
categoriesMap = CategoryBuilder.createDefaultHierarchy(categoryRepository);
}
public void test_should_update_running_balance_for_single_account() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(1234).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 2234);
assertFinalBalanceForAccount(a1, 2234);
}
public void test_should_update_running_balance_for_single_account_with_transactions_having_exactly_the_same_datetime() {
DateTime dt = DateTime.fromTimestamp(System.currentTimeMillis());
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(dt).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(2000).dateTime(dt).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(3000).dateTime(dt).create();
Transaction t4 = TransactionBuilder.withDb(db).account(a1).amount(4000).dateTime(dt).create();
Transaction t5 = TransactionBuilder.withDb(db).account(a1).amount(5000).dateTime(dt).create();
assertFinalBalanceForAccount(a1, 15000);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 3000);
assertAccountBalanceForTransaction(t3, a1, 6000);
assertAccountBalanceForTransaction(t4, a1, 10000);
assertAccountBalanceForTransaction(t5, a1, 15000);
db.rebuildRunningBalanceForAccount(a1);
assertFinalBalanceForAccount(a1, 15000);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 3000);
assertAccountBalanceForTransaction(t3, a1, 6000);
assertAccountBalanceForTransaction(t4, a1, 10000);
assertAccountBalanceForTransaction(t5, a1, 15000);
}
public void test_should_not_duplicate_running_balance_with_splits() {
// add new transaction before split
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(2000).create();
db.rebuildRunningBalanceForAccount(a1);
// insert new split
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(1000)
.withSplit(categoriesMap.get("A"), 600)
.withSplit(categoriesMap.get("B"), 400).create();
assertAccountBalanceForTransaction(t1, a1, 2000);
assertAccountBalanceForTransaction(t2, a1, 3000);
assertFinalBalanceForAccount(a1, 3000);
// add new transaction after split
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-1500).create();
assertAccountBalanceForTransaction(t1, a1, 2000);
assertAccountBalanceForTransaction(t2, a1, 3000);
assertAccountBalanceForTransaction(t3, a1, 1500);
assertFinalBalanceForAccount(a1, 1500);
// rebuild balance
db.rebuildRunningBalances();
assertAccountBalanceForTransaction(t1, a1, 2000);
assertAccountBalanceForTransaction(t2, a1, 3000);
assertAccountBalanceForTransaction(t3, a1, 1500);
assertFinalBalanceForAccount(a1, 1500);
}
public void test_should_update_running_balance_for_two_accounts() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a2).amount(2000).create();
Transaction t3 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-500).toAccount(a2).toAmount(500).create();
db.rebuildRunningBalances();
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a2, 2000);
assertAccountBalanceForTransaction(t3, a1, 500);
assertAccountBalanceForTransaction(t3, a2, 2500);
assertFinalBalanceForAccount(a1, 500);
assertFinalBalanceForAccount(a2, 2500);
}
public void test_should_update_running_balance_for_account_which_has_transfer_to_the_same_account() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a2).amount(2000).create();
Transaction t3 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-500).toAccount(a1).toAmount(500).create();
db.rebuildRunningBalances();
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a2, 2000);
assertAccountBalanceForTransaction(t3, a1, 0);
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 2000);
}
public void test_should_update_running_balance_for_two_accounts_with_transfer_split() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a2).amount(2000).create();
db.rebuildRunningBalances();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-100)
.withTransferSplit(a2, -100, 50).create();
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a2, 2000);
assertAccountBalanceForTransaction(t3, a1, 900);
List<Transaction> splits = db.getSplitsForTransaction(t3.id);
assertEquals(1, splits.size());
// running balance is attach to the split, not to the parent transaction!
assertAccountBalanceForTransaction(splits.get(0), a2, 2050);
assertFinalBalanceForAccount(a1, 900);
assertFinalBalanceForAccount(a2, 2050);
db.rebuildRunningBalances();
assertAccountBalanceForTransaction(splits.get(0), a2, 2050);
assertFinalBalanceForAccount(a1, 900);
assertFinalBalanceForAccount(a2, 2050);
}
public void test_should_update_running_balance_for_two_accounts_with_transfer_split_with_multiple_transfers() {
TransactionBuilder.withDb(db).account(a1).amount(2000).create();
TransactionBuilder.withDb(db).account(a2).amount(3000).create();
TransactionBuilder.withDb(db).account(a3).amount(4000).create();
db.rebuildRunningBalances();
Transaction t4 = TransactionBuilder.withDb(db).account(a1).amount(-1000)
.withTransferSplit(a2, -100, 50)
.withTransferSplit(a2, -200, 60)
.withTransferSplit(a2, -300, 70)
.withTransferSplit(a3, -100, 80)
.withTransferSplit(a3, -300, 90)
.create();
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 3180);
assertFinalBalanceForAccount(a3, 4170);
List<Transaction> splits = db.getSplitsForTransaction(t4.id);
assertEquals(5, splits.size());
assertAccountBalanceForTransaction(splits.get(0), a2, 3050);
assertAccountBalanceForTransaction(splits.get(1), a2, 3110);
assertAccountBalanceForTransaction(splits.get(2), a2, 3180);
assertAccountBalanceForTransaction(splits.get(3), a3, 4080);
assertAccountBalanceForTransaction(splits.get(4), a3, 4170);
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 3180);
assertFinalBalanceForAccount(a3, 4170);
db.deleteTransaction(t4.id);
assertFinalBalanceForAccount(a1, 2000);
assertFinalBalanceForAccount(a2, 3000);
assertFinalBalanceForAccount(a3, 4000);
}
public void test_should_update_running_balance_for_two_accounts_when_updating_transfer_split() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a2).amount(2000).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-100)
.withTransferSplit(a2, -100, 50).create();
Transaction t4 = TransactionBuilder.withDb(db).account(a1).amount(-100).create();
Transaction t5 = TransactionBuilder.withDb(db).account(a2).amount(-100).create();
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 800);
assertFinalBalanceForAccount(a2, 1950);
// update split -100 -> +50 >>> -200 -> +100
List<Transaction> splits = db.getSplitsForTransaction(t3.id);
t3.fromAmount = -200;
splits.get(0).fromAmount = -200;
splits.get(0).toAmount = 100;
t3.splits = splits;
db.insertOrUpdate(t3);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a2, 2000);
assertAccountBalanceForTransaction(t3, a1, 800);
assertAccountBalanceForTransaction(t4, a1, 700);
assertAccountBalanceForTransaction(t5, a2, 2000);
assertFinalBalanceForAccount(a1, 700);
assertFinalBalanceForAccount(a2, 2000);
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 700);
assertFinalBalanceForAccount(a2, 2000);
}
public void test_should_update_running_balance_when_deleting_transfer_split() {
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a2).amount(2000).create();
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 2000);
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-200)
.withTransferSplit(a2, -200, 100).create();
assertFinalBalanceForAccount(a1, 800);
assertFinalBalanceForAccount(a2, 2100);
db.deleteTransaction(t3.id);
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 2000);
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 1000);
assertFinalBalanceForAccount(a2, 2000);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a2, 2000);
}
public void test_should_update_running_balance_when_inserting_new_transaction() {
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
// t4 | 13:20 | +100 | +350 <- insert at the bottom
Transaction t4 = TransactionBuilder.withDb(db).account(a1).amount(100).dateTime(DateTime.today().at(13,20,0,0)).create();
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertAccountBalanceForTransaction(t4, a1, 350);
assertFinalBalanceForAccount(a1, 350);
assertLastTransactionDate(a1, DateTime.today().at(13,20,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t5 | 11:10 | -50 | +450 <- insert in the middle
// t3 | 12:00 | -250 | +200
// t4 | 13:20 | +100 | +300
Transaction t5 = TransactionBuilder.withDb(db).account(a1).amount(-50).dateTime(DateTime.today().at(11,10,0,0)).create();
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t5, a1, 450);
assertAccountBalanceForTransaction(t3, a1, 200);
assertAccountBalanceForTransaction(t4, a1, 300);
assertFinalBalanceForAccount(a1, 300);
assertLastTransactionDate(a1, DateTime.today().at(13,20,0,0));
// * | time | amount | balance
// t6 | 10:00 | +150 | +150 <- insert at the top
// t1 | 11:00 | +1000 | +1150
// t2 | 11:05 | -500 | +650
// t5 | 11:10 | -50 | +600
// t3 | 12:00 | -250 | +350
// t4 | 13:20 | +100 | +450
Transaction t6 = TransactionBuilder.withDb(db).account(a1).amount(150).dateTime(DateTime.today().at(10,0,0,0)).create();
assertAccountBalanceForTransaction(t6, a1, 150);
assertAccountBalanceForTransaction(t1, a1, 1150);
assertAccountBalanceForTransaction(t2, a1, 650);
assertAccountBalanceForTransaction(t5, a1, 600);
assertAccountBalanceForTransaction(t3, a1, 350);
assertAccountBalanceForTransaction(t4, a1, 450);
assertFinalBalanceForAccount(a1, 450);
assertLastTransactionDate(a1, DateTime.today().at(13,20,0,0));
}
public void test_should_update_running_balance_when_updating_amount_on_existing_transaction() {
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -350 | +150 <- update at the bottom
t3.fromAmount = -350;
db.insertOrUpdate(t3);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 150);
assertFinalBalanceForAccount(a1, 150);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -400 | +600 <- update in the middle
// t3 | 12:00 | -350 | +250
t2.fromAmount = -400;
db.insertOrUpdate(t2);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 600);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1200 | +1200 <- update at the top
// t2 | 11:05 | -400 | +800
// t3 | 12:00 | -350 | +450
t1.fromAmount = 1200;
db.insertOrUpdate(t1);
assertAccountBalanceForTransaction(t1, a1, 1200);
assertAccountBalanceForTransaction(t2, a1, 800);
assertAccountBalanceForTransaction(t3, a1, 450);
assertFinalBalanceForAccount(a1, 450);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
}
public void test_should_update_running_balance_when_updating_datetime_on_existing_transaction() {
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t3 | 11:01 | -250 | +750 <- move up
// t2 | 11:05 | -500 | +250
t3.dateTime = DateTime.today().at(11,1,0,0).asLong();
db.insertOrUpdate(t3);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t3, a1, 750);
assertAccountBalanceForTransaction(t2, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(11,5,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:05 | -250 | +250 <- move down
t3.dateTime = DateTime.today().at(12,5,0,0).asLong();
db.insertOrUpdate(t3);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,5,0,0));
}
public void test_should_update_running_balance_when_updating_account_on_existing_transaction() {
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t22 | 12:00 | -100 | +800
Transaction t11 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t12 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t21 = TransactionBuilder.withDb(db).account(a2).amount(900).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t22 = TransactionBuilder.withDb(db).account(a2).amount(-100).dateTime(DateTime.today().at(13,0,0,0)).create();
db.rebuildRunningBalances();
assertFinalBalanceForAccount(a1, 500);
assertFinalBalanceForAccount(a2, 800);
assertLastTransactionDate(a1, DateTime.today().at(11,5,0,0));
assertLastTransactionDate(a2, DateTime.today().at(13,0,0,0));
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t22 | 12:00 | -100 | +400
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
t22.fromAccountId = a1.id;
db.insertOrUpdate(t22);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t22, a1, 400);
assertFinalBalanceForAccount(a1, 400);
assertAccountBalanceForTransaction(t21, a2, 900);
assertFinalBalanceForAccount(a2, 900);
assertLastTransactionDate(a1, DateTime.today().at(13,0,0,0));
assertLastTransactionDate(a2, DateTime.today().at(11,0,0,0));
}
public void test_should_update_running_balance_when_deleting_existing_transaction() {
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
// t4 | 13:00 | -50 | +200
Transaction t1 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t2 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t3 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
Transaction t4 = TransactionBuilder.withDb(db).account(a1).amount(-50).dateTime(DateTime.today().at(13,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertAccountBalanceForTransaction(t4, a1, 200);
assertFinalBalanceForAccount(a1, 200);
assertLastTransactionDate(a1, DateTime.today().at(13,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | -500 | +500
// t3 | 12:00 | -250 | +250
// t4 | 13:00 | * | * <- delete at the bottom
db.deleteTransaction(t4.id);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t2, a1, 500);
assertAccountBalanceForTransaction(t3, a1, 250);
assertFinalBalanceForAccount(a1, 250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | +1000 | +1000
// t2 | 11:05 | * | * <- delete in the middle
// t3 | 12:00 | -250 | +750
db.deleteTransaction(t2.id);
assertAccountBalanceForTransaction(t1, a1, 1000);
assertAccountBalanceForTransaction(t3, a1, 750);
assertFinalBalanceForAccount(a1, 750);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
// * | time | amount | balance
// t1 | 11:00 | * | * <- delete at the top
// t3 | 12:00 | -250 | -250
db.deleteTransaction(t1.id);
assertAccountBalanceForTransaction(t3, a1, -250);
assertFinalBalanceForAccount(a1, -250);
assertLastTransactionDate(a1, DateTime.today().at(12,0,0,0));
}
public void test_should_update_running_balance_when_inserting_new_transfer() {
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t22 | 12:00 | -100 | +800
Transaction t11 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t12 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t13 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t13, a1, 250);
assertFinalBalanceForAccount(a1, 250);
Transaction t21 = TransactionBuilder.withDb(db).account(a2).amount(900).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t22 = TransactionBuilder.withDb(db).account(a2).amount(-100).dateTime(DateTime.today().at(13,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a2);
assertAccountBalanceForTransaction(t21, a2, 900);
assertAccountBalanceForTransaction(t22, a2, 800);
assertFinalBalanceForAccount(a2, 800);
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// t14 | 12:30 | -100 | +150 -> A2
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t14 | 12:30 | +100 | +1000 <- A1
// t22 | 13:00 | -100 | +900
Transaction t14 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(100).dateTime(DateTime.today().at(12,30,0,0)).create();
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t13, a1, 250);
assertAccountBalanceForTransaction(t14, a1, 150);
assertFinalBalanceForAccount(a1, 150);
assertAccountBalanceForTransaction(t21, a2, 900);
assertAccountBalanceForTransaction(t14, a2, 1000);
assertAccountBalanceForTransaction(t22, a2, 900);
assertFinalBalanceForAccount(a2, 900);
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// t14 | 12:30 | -100 | +150 -> A2
// t15 | 13:30 | -50 | +100 -> A2 (rate=0.4)
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t14 | 12:30 | +100 | +1000 <- A1
// t22 | 13:00 | -100 | +900
// t15 | 13:30 | +20 | +920 <- A1
Transaction t15 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-50).toAccount(a2).toAmount(20).dateTime(DateTime.today().at(13,30,0,0)).create();
assertAccountBalanceForTransaction(t15, a1, 100);
assertFinalBalanceForAccount(a1, 100);
assertAccountBalanceForTransaction(t15, a2, 920);
assertFinalBalanceForAccount(a2, 920);
}
public void test_should_update_running_balance_when_updating_amount_on_existing_transfer() {
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// t14 | 12:30 | -100 | +150 -> A2
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t14 | 12:30 | +100 | +1000 <- A1
// t22 | 13:00 | -100 | +900
Transaction t11 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t12 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t13 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
Transaction t21 = TransactionBuilder.withDb(db).account(a2).amount(900).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t22 = TransactionBuilder.withDb(db).account(a2).amount(-100).dateTime(DateTime.today().at(13,0,0,0)).create();
Transaction t14 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(100).dateTime(DateTime.today().at(12,30,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
db.rebuildRunningBalanceForAccount(a2);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t13, a1, 250);
assertAccountBalanceForTransaction(t14, a1, 150);
assertFinalBalanceForAccount(a1, 150);
assertAccountBalanceForTransaction(t21, a2, 900);
assertAccountBalanceForTransaction(t14, a2, 1000);
assertAccountBalanceForTransaction(t22, a2, 900);
assertFinalBalanceForAccount(a2, 900);
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// t14 | 12:30 | -200 | +50 -> A2 <- update amount
// A2 | time | amount | balance
// t21 | 11:00 | +900 | +900
// t14 | 12:30 | +250 | +1150 <- A1 <- update amount
// t22 | 13:00 | -100 | +1050
t14.fromAmount = -200;
t14.toAmount = +250;
db.insertOrUpdate(t14);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t13, a1, 250);
assertAccountBalanceForTransaction(t14, a1, 50);
assertFinalBalanceForAccount(a1, 50);
assertAccountBalanceForTransaction(t21, a2, 900);
assertAccountBalanceForTransaction(t14, a2, 1150);
assertAccountBalanceForTransaction(t22, a2, 1050);
assertFinalBalanceForAccount(a2, 1050);
}
public void test_should_update_running_balance_when_updating_datetime_on_existing_transfer() {
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t13 | 12:00 | -250 | +250
// t14 | 12:30 | -100 | +150 -> A2
// A2 | time | amount | balance
// t21 | 12:00 | +900 | +900
// t14 | 12:30 | +100 | +1000 <- A1
// t22 | 13:00 | -100 | +900
Transaction t11 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t12 = TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
Transaction t13 = TransactionBuilder.withDb(db).account(a1).amount(-250).dateTime(DateTime.today().at(12,0,0,0)).create();
Transaction t21 = TransactionBuilder.withDb(db).account(a2).amount(900).dateTime(DateTime.today().at(12,0,0,0)).create();
Transaction t22 = TransactionBuilder.withDb(db).account(a2).amount(-100).dateTime(DateTime.today().at(13,0,0,0)).create();
Transaction t14 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(100).dateTime(DateTime.today().at(12,30,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
db.rebuildRunningBalanceForAccount(a2);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t13, a1, 250);
assertAccountBalanceForTransaction(t14, a1, 150);
assertFinalBalanceForAccount(a1, 150);
assertAccountBalanceForTransaction(t21, a2, 900);
assertAccountBalanceForTransaction(t14, a2, 1000);
assertAccountBalanceForTransaction(t22, a2, 900);
assertFinalBalanceForAccount(a2, 900);
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 11:05 | -500 | +500
// t14 | 11:10 | -100 | +400 -> A2 <- move up
// t13 | 12:00 | -250 | +150
// A2 | time | amount | balance
// t14 | 11:10 | +100 | +100 <- A1
// t21 | 12:00 | +900 | +1000
// t22 | 13:00 | -100 | +900
t14.dateTime = DateTime.today().at(11,10,0,0).asLong();
db.insertOrUpdate(t14);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 500);
assertAccountBalanceForTransaction(t14, a1, 400);
assertAccountBalanceForTransaction(t13, a1, 150);
assertFinalBalanceForAccount(a1, 150);
assertAccountBalanceForTransaction(t14, a2, 100);
assertAccountBalanceForTransaction(t21, a2, 1000);
assertAccountBalanceForTransaction(t22, a2, 900);
assertFinalBalanceForAccount(a2, 900);
}
public void test_should_update_running_balance_when_updating_account_on_existing_transfer() {
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 12:30 | -100 | +900 -> A2
// A2 | time | amount | balance
// t21 | 12:00 | +500 | +500
// t12 | 12:30 | +100 | +600 <- A1
// A3 | time | amount | balance
// t31 | 13:00 | +100 | +100
Transaction t11 = TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
Transaction t21 = TransactionBuilder.withDb(db).account(a2).amount(500).dateTime(DateTime.today().at(12,0,0,0)).create();
Transaction t12 = TransferBuilder.withDb(db).fromAccount(a1).fromAmount(-100).toAccount(a2).toAmount(100).dateTime(DateTime.today().at(12,30,0,0)).create();
Transaction t31 = TransactionBuilder.withDb(db).account(a3).amount(100).dateTime(DateTime.today().at(13,0,0,0)).create();
db.rebuildRunningBalanceForAccount(a1);
db.rebuildRunningBalanceForAccount(a2);
db.rebuildRunningBalanceForAccount(a3);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 900);
assertFinalBalanceForAccount(a1, 900);
assertAccountBalanceForTransaction(t21, a2, 500);
assertAccountBalanceForTransaction(t12, a2, 600);
assertFinalBalanceForAccount(a2, 600);
assertAccountBalanceForTransaction(t31, a3, 100);
assertFinalBalanceForAccount(a3, 100);
// A1 | time | amount | balance
// t11 | 11:00 | +1000 | +1000
// t12 | 12:30 | -100 | +900 -> A3 <- update account
// A2 | time | amount | balance
// t21 | 12:00 | +500 | +500
// A3 | time | amount | balance
// t12 | 12:30 | +100 | +100 <- A1
// t31 | 13:00 | +100 | +200
t12.toAccountId = a3.id;
db.insertOrUpdate(t12);
assertAccountBalanceForTransaction(t11, a1, 1000);
assertAccountBalanceForTransaction(t12, a1, 900);
assertFinalBalanceForAccount(a1, 900);
assertAccountBalanceForTransaction(t21, a2, 500);
assertFinalBalanceForAccount(a2, 500);
assertAccountBalanceForTransaction(t12, a3, 100);
assertAccountBalanceForTransaction(t31, a3, 200);
assertFinalBalanceForAccount(a3, 200);
}
public void test_should_update_accounts_last_transaction_date() {
TransactionBuilder.withDb(db).account(a1).amount(1000).dateTime(DateTime.today().at(11,0,0,0)).create();
TransactionBuilder.withDb(db).account(a1).amount(-500).dateTime(DateTime.today().at(11,5,0,0)).create();
TransactionBuilder.withDb(db).account(a2).amount(900).dateTime(DateTime.today().at(11,0,0,0)).create();
TransactionBuilder.withDb(db).account(a2).amount(-100).dateTime(DateTime.today().at(13,0,0,0)).create();
resetLastTransaction(a1);
resetLastTransaction(a2);
assertLastTransactionDate(a1, DateTime.NULL_DATE);
assertLastTransactionDate(a2, DateTime.NULL_DATE);
db.updateAccountsLastTransactionDate();
assertLastTransactionDate(a1, DateTime.today().at(11,5,0,0));
assertLastTransactionDate(a2, DateTime.today().at(13,0,0,0));
}
private void resetLastTransaction(Account a) {
db.db().execSQL("update account set last_transaction_date=0 where _id=?", new String[]{String.valueOf(a.id)});
}
}