diff --git a/config/locales/views/accounts/en.yml b/config/locales/views/accounts/en.yml
index 6a55b619..755b7b8e 100644
--- a/config/locales/views/accounts/en.yml
+++ b/config/locales/views/accounts/en.yml
@@ -66,7 +66,6 @@ en:
sync:
success: Account sync started
sync_all:
- no_accounts_to_sync: No accounts were eligible for syncing.
- success: Successfully queued %{count} accounts for syncing.
+ success: Successfully queued accounts for syncing.
update:
success: Account updated
diff --git a/db/migrate/20240707130331_create_account_syncs.rb b/db/migrate/20240707130331_create_account_syncs.rb
new file mode 100644
index 00000000..474a98a0
--- /dev/null
+++ b/db/migrate/20240707130331_create_account_syncs.rb
@@ -0,0 +1,18 @@
+class CreateAccountSyncs < ActiveRecord::Migration[7.2]
+ def change
+ create_table :account_syncs, id: :uuid do |t|
+ t.references :account, null: false, foreign_key: true, type: :uuid
+ t.string :status, null: false, default: "pending"
+ t.date :start_date
+ t.datetime :last_ran_at
+ t.string :error
+ t.text :warnings, array: true, default: []
+
+ t.timestamps
+ end
+
+ remove_column :accounts, :status, :string
+ remove_column :accounts, :sync_warnings, :jsonb
+ remove_column :accounts, :sync_errors, :jsonb
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index e13e7f6d..91cbbdbd 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -48,6 +48,18 @@ ActiveRecord::Schema[7.2].define(version: 2024_07_09_152243) do
t.index ["transfer_id"], name: "index_account_entries_on_transfer_id"
end
+ create_table "account_syncs", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
+ t.uuid "account_id", null: false
+ t.string "status", default: "pending", null: false
+ t.date "start_date"
+ t.datetime "last_ran_at"
+ t.string "error"
+ t.text "warnings", default: [], array: true
+ t.datetime "created_at", null: false
+ t.datetime "updated_at", null: false
+ t.index ["account_id"], name: "index_account_syncs_on_account_id"
+ end
+
create_table "account_transactions", id: :uuid, default: -> { "gen_random_uuid()" }, force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@@ -80,12 +92,9 @@ ActiveRecord::Schema[7.2].define(version: 2024_07_09_152243) do
t.decimal "balance", precision: 19, scale: 4, default: "0.0"
t.string "currency", default: "USD"
t.boolean "is_active", default: true, null: false
- t.enum "status", default: "ok", null: false, enum_type: "account_status"
- t.jsonb "sync_warnings", default: [], null: false
- t.jsonb "sync_errors", default: [], null: false
t.date "last_sync_date"
t.uuid "institution_id"
- t.virtual "classification", type: :string, as: "\nCASE\n WHEN ((accountable_type)::text = ANY (ARRAY[('Loan'::character varying)::text, ('CreditCard'::character varying)::text, ('OtherLiability'::character varying)::text])) THEN 'liability'::text\n ELSE 'asset'::text\nEND", stored: true
+ t.virtual "classification", type: :string, as: "\nCASE\n WHEN ((accountable_type)::text = ANY ((ARRAY['Loan'::character varying, 'CreditCard'::character varying, 'OtherLiability'::character varying])::text[])) THEN 'liability'::text\n ELSE 'asset'::text\nEND", stored: true
t.index ["accountable_type"], name: "index_accounts_on_accountable_type"
t.index ["family_id"], name: "index_accounts_on_family_id"
t.index ["institution_id"], name: "index_accounts_on_institution_id"
@@ -364,6 +373,7 @@ ActiveRecord::Schema[7.2].define(version: 2024_07_09_152243) do
add_foreign_key "account_balances", "accounts", on_delete: :cascade
add_foreign_key "account_entries", "account_transfers", column: "transfer_id"
add_foreign_key "account_entries", "accounts"
+ add_foreign_key "account_syncs", "accounts"
add_foreign_key "account_transactions", "categories", on_delete: :nullify
add_foreign_key "account_transactions", "merchants"
add_foreign_key "accounts", "families"
diff --git a/lib/tasks/demo_data.rake b/lib/tasks/demo_data.rake
index 556ac270..3fce0461 100644
--- a/lib/tasks/demo_data.rake
+++ b/lib/tasks/demo_data.rake
@@ -323,9 +323,7 @@ namespace :demo_data do
puts "Syncing accounts... This may take a few seconds."
- family.accounts.each do |account|
- account.sync
- end
+ family.sync
puts "Accounts synced. Demo data reset complete."
end
diff --git a/test/controllers/account/entries_controller_test.rb b/test/controllers/account/entries_controller_test.rb
index 327d13f3..48e2c1c1 100644
--- a/test/controllers/account/entries_controller_test.rb
+++ b/test/controllers/account/entries_controller_test.rb
@@ -3,49 +3,48 @@ require "test_helper"
class Account::EntriesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in @user = users(:family_admin)
- @account = accounts(:savings)
- @transaction_entry = @account.entries.account_transactions.first
- @valuation_entry = @account.entries.account_valuations.first
+ @transaction = account_entries :transaction
+ @valuation = account_entries :valuation
end
test "should edit valuation entry" do
- get edit_account_entry_url(@account, @valuation_entry)
+ get edit_account_entry_url(@valuation.account, @valuation)
assert_response :success
end
test "should show transaction entry" do
- get account_entry_url(@account, @transaction_entry)
+ get account_entry_url(@transaction.account, @transaction)
assert_response :success
end
test "should show valuation entry" do
- get account_entry_url(@account, @valuation_entry)
+ get account_entry_url(@valuation.account, @valuation)
assert_response :success
end
test "should get list of transaction entries" do
- get transaction_account_entries_url(@account)
+ get transaction_account_entries_url(@transaction.account)
assert_response :success
end
test "should get list of valuation entries" do
- get valuation_account_entries_url(@account)
+ get valuation_account_entries_url(@valuation.account)
assert_response :success
end
test "gets new entry by type" do
- get new_account_entry_url(@account, entryable_type: "Account::Valuation")
+ get new_account_entry_url(@valuation.account, entryable_type: "Account::Valuation")
assert_response :success
end
test "should create valuation" do
assert_difference [ "Account::Entry.count", "Account::Valuation.count" ], 1 do
- post account_entries_url(@account), params: {
+ post account_entries_url(@valuation.account), params: {
account_entry: {
name: "Manual valuation",
amount: 19800,
date: Date.current,
- currency: @account.currency,
+ currency: @valuation.account.currency,
entryable_type: "Account::Valuation",
entryable_attributes: {}
}
@@ -54,16 +53,16 @@ class Account::EntriesControllerTest < ActionDispatch::IntegrationTest
assert_equal "Valuation created", flash[:notice]
assert_enqueued_with job: AccountSyncJob
- assert_redirected_to account_path(@account)
+ assert_redirected_to account_path(@valuation.account)
end
test "error when valuation already exists for date" do
assert_no_difference_in_entries do
- post account_entries_url(@account), params: {
+ post account_entries_url(@valuation.account), params: {
account_entry: {
amount: 19800,
- date: @valuation_entry.date,
- currency: @valuation_entry.currency,
+ date: @valuation.date,
+ currency: @valuation.currency,
entryable_type: "Account::Valuation",
entryable_attributes: {}
}
@@ -71,33 +70,33 @@ class Account::EntriesControllerTest < ActionDispatch::IntegrationTest
end
assert_equal "Date has already been taken", flash[:error]
- assert_redirected_to account_path(@account)
+ assert_redirected_to account_path(@valuation.account)
end
test "can update entry without entryable attributes" do
assert_no_difference_in_entries do
- patch account_entry_url(@account, @valuation_entry), params: {
+ patch account_entry_url(@valuation.account, @valuation), params: {
account_entry: {
name: "Updated name"
}
}
end
- assert_redirected_to account_entry_url(@account, @valuation_entry)
+ assert_redirected_to account_entry_url(@valuation.account, @valuation)
assert_enqueued_with(job: AccountSyncJob)
end
test "should update transaction entry with entryable attributes" do
assert_no_difference_in_entries do
- patch account_entry_url(@account, @transaction_entry), params: {
+ patch account_entry_url(@transaction.account, @transaction), params: {
account_entry: {
name: "Updated name",
date: Date.current,
currency: "USD",
amount: 20,
- entryable_type: @transaction_entry.entryable_type,
+ entryable_type: @transaction.entryable_type,
entryable_attributes: {
- id: @transaction_entry.entryable_id,
+ id: @transaction.entryable_id,
tag_ids: [ Tag.first.id, Tag.second.id ],
category_id: Category.first.id,
merchant_id: Merchant.first.id,
@@ -108,17 +107,17 @@ class Account::EntriesControllerTest < ActionDispatch::IntegrationTest
}
end
- assert_redirected_to account_entry_url(@account, @transaction_entry)
+ assert_redirected_to account_entry_url(@transaction.account, @transaction)
assert_enqueued_with(job: AccountSyncJob)
end
test "should destroy transaction entry" do
- [ @transaction_entry, @valuation_entry ].each do |entry|
+ [ @transaction, @valuation ].each do |entry|
assert_difference -> { Account::Entry.count } => -1, -> { entry.entryable_class.count } => -1 do
- delete account_entry_url(@account, entry)
+ delete account_entry_url(entry.account, entry)
end
- assert_redirected_to account_url(@account)
+ assert_redirected_to account_url(entry.account)
assert_enqueued_with(job: AccountSyncJob)
end
end
diff --git a/test/controllers/account/transfers_controller_test.rb b/test/controllers/account/transfers_controller_test.rb
index 5b28c1b2..a41426bf 100644
--- a/test/controllers/account/transfers_controller_test.rb
+++ b/test/controllers/account/transfers_controller_test.rb
@@ -14,8 +14,8 @@ class Account::TransfersControllerTest < ActionDispatch::IntegrationTest
assert_difference "Account::Transfer.count", 1 do
post account_transfers_url, params: {
account_transfer: {
- from_account_id: accounts(:checking).id,
- to_account_id: accounts(:savings).id,
+ from_account_id: accounts(:depository).id,
+ to_account_id: accounts(:credit_card).id,
date: Date.current,
amount: 100,
currency: "USD",
@@ -28,7 +28,7 @@ class Account::TransfersControllerTest < ActionDispatch::IntegrationTest
test "can destroy transfer" do
assert_difference -> { Account::Transfer.count } => -1, -> { Account::Transaction.count } => 0 do
- delete account_transfer_url(account_transfers(:credit_card_payment))
+ delete account_transfer_url(account_transfers(:one))
end
end
end
diff --git a/test/controllers/accounts_controller_test.rb b/test/controllers/accounts_controller_test.rb
index 629a19bd..a7b32d09 100644
--- a/test/controllers/accounts_controller_test.rb
+++ b/test/controllers/accounts_controller_test.rb
@@ -3,7 +3,7 @@ require "test_helper"
class AccountsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in @user = users(:family_admin)
- @account = accounts(:checking)
+ @account = accounts(:depository)
end
test "gets accounts list" do
@@ -33,7 +33,7 @@ class AccountsControllerTest < ActionDispatch::IntegrationTest
test "can sync all accounts" do
post sync_all_accounts_path
assert_redirected_to accounts_url
- assert_equal "Successfully queued #{ @user.family.accounts.size } accounts for syncing.", flash[:notice]
+ assert_equal "Successfully queued accounts for syncing.", flash[:notice]
end
test "should update account" do
diff --git a/test/controllers/categories_controller_test.rb b/test/controllers/categories_controller_test.rb
index b9fed5b0..cc71a340 100644
--- a/test/controllers/categories_controller_test.rb
+++ b/test/controllers/categories_controller_test.rb
@@ -3,6 +3,7 @@ require "test_helper"
class CategoriesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:family_admin)
+ @transaction = account_transactions :one
end
test "index" do
@@ -37,7 +38,7 @@ class CategoriesControllerTest < ActionDispatch::IntegrationTest
assert_difference "Category.count", +1 do
post categories_url, params: {
- transaction_id: account_transactions(:checking_one).id,
+ transaction_id: @transaction.id,
category: {
name: "New Category",
color: color } }
@@ -48,7 +49,7 @@ class CategoriesControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to transactions_url
assert_equal "New Category", new_category.name
assert_equal color, new_category.color
- assert_equal account_transactions(:checking_one).reload.category, new_category
+ assert_equal @transaction.reload.category, new_category
end
test "edit" do
diff --git a/test/controllers/tag/deletions_controller_test.rb b/test/controllers/tag/deletions_controller_test.rb
index 57bf6df2..d51af30f 100644
--- a/test/controllers/tag/deletions_controller_test.rb
+++ b/test/controllers/tag/deletions_controller_test.rb
@@ -3,8 +3,7 @@ require "test_helper"
class Tag::DeletionsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in @user = users(:family_admin)
- @user_tags = @user.family.tags
- @tag = tags(:hawaii_trip)
+ @tag = tags(:one)
end
test "should get new" do
@@ -13,7 +12,7 @@ class Tag::DeletionsControllerTest < ActionDispatch::IntegrationTest
end
test "create with replacement" do
- replacement_tag = tags(:trips)
+ replacement_tag = tags(:two)
affected_transaction_count = @tag.transactions.count
diff --git a/test/controllers/transactions_controller_test.rb b/test/controllers/transactions_controller_test.rb
index 3f381261..5ef4d356 100644
--- a/test/controllers/transactions_controller_test.rb
+++ b/test/controllers/transactions_controller_test.rb
@@ -1,10 +1,11 @@
require "test_helper"
class TransactionsControllerTest < ActionDispatch::IntegrationTest
+ include Account::EntriesTestHelper
+
setup do
sign_in @user = users(:family_admin)
- @transaction_entry = account_entries(:checking_one)
- @recent_transaction_entries = @user.family.entries.account_transactions.reverse_chronological.limit(20).to_a
+ @transaction = account_entries(:transaction)
end
test "should get new" do
@@ -13,9 +14,9 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
end
test "prefills account_id" do
- get new_transaction_url(account_id: @transaction_entry.account.id)
+ get new_transaction_url(account_id: @transaction.account.id)
assert_response :success
- assert_select "option[selected][value='#{@transaction_entry.account.id}']"
+ assert_select "option[selected][value='#{@transaction.account.id}']"
end
test "should create transaction" do
@@ -45,11 +46,11 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
post transactions_url, params: {
account_entry: {
nature: "expense",
- account_id: @transaction_entry.account_id,
- amount: @transaction_entry.amount,
- currency: @transaction_entry.currency,
- date: @transaction_entry.date,
- name: @transaction_entry.name,
+ account_id: @transaction.account_id,
+ amount: @transaction.amount,
+ currency: @transaction.currency,
+ date: @transaction.date,
+ name: @transaction.name,
entryable_type: "Account::Transaction",
entryable_attributes: {}
}
@@ -58,7 +59,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
created_entry = Account::Entry.order(created_at: :desc).first
- assert_redirected_to account_url(@transaction_entry.account)
+ assert_redirected_to account_url(@transaction.account)
assert created_entry.amount.positive?, "Amount should be positive"
end
@@ -67,11 +68,11 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
post transactions_url, params: {
account_entry: {
nature: "income",
- account_id: @transaction_entry.account_id,
- amount: @transaction_entry.amount,
- currency: @transaction_entry.currency,
- date: @transaction_entry.date,
- name: @transaction_entry.name,
+ account_id: @transaction.account_id,
+ amount: @transaction.amount,
+ currency: @transaction.currency,
+ date: @transaction.date,
+ name: @transaction.name,
entryable_type: "Account::Transaction",
entryable_attributes: { category_id: categories(:food_and_drink).id }
}
@@ -80,83 +81,79 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
created_entry = Account::Entry.order(created_at: :desc).first
- assert_redirected_to account_url(@transaction_entry.account)
+ assert_redirected_to account_url(@transaction.account)
assert created_entry.amount.negative?, "Amount should be negative"
end
- test "should get paginated index with most recent transactions first" do
- get transactions_url(per_page: 10)
- assert_response :success
-
- @recent_transaction_entries.first(10).each do |transaction|
- assert_dom "#" + dom_id(transaction), count: 1
- end
- end
-
test "transaction count represents filtered total" do
+ family = families(:empty)
+ sign_in family.users.first
+ account = family.accounts.create! name: "Test", balance: 0, accountable: Depository.new
+
+ 3.times do
+ create_transaction(account: account)
+ end
+
get transactions_url(per_page: 10)
- assert_dom "#total-transactions", count: 1, text: @user.family.entries.account_transactions.select { |t| t.currency == "USD" }.count.to_s
- new_transaction = @user.family.accounts.first.entries.create! \
- entryable: Account::Transaction.new,
- name: "Transaction to search for",
- date: Date.current,
- amount: 0,
- currency: "USD"
+ assert_dom "#total-transactions", count: 1, text: family.entries.account_transactions.size.to_s
- get transactions_url(q: { search: new_transaction.name })
+ searchable_transaction = create_transaction(account: account, name: "Unique test name")
+
+ get transactions_url(q: { search: searchable_transaction.name })
# Only finds 1 transaction that matches filter
- assert_dom "#" + dom_id(new_transaction), count: 1
+ assert_dom "#" + dom_id(searchable_transaction), count: 1
assert_dom "#total-transactions", count: 1, text: "1"
end
- test "can navigate to paginated result" do
- get transactions_url(page: 2, per_page: 10)
+ test "can paginate" do
+ family = families(:empty)
+ sign_in family.users.first
+ account = family.accounts.create! name: "Test", balance: 0, accountable: Depository.new
+
+ 11.times do
+ create_transaction(account: account)
+ end
+
+ sorted_transactions = family.entries.account_transactions.reverse_chronological.to_a
+
+ assert_equal 11, sorted_transactions.count
+
+ get transactions_url(page: 1, per_page: 10)
+
assert_response :success
-
- visible_transaction_entries = @recent_transaction_entries[10, 10].reject { |e| e.transfer.present? }
-
- visible_transaction_entries.each do |transaction|
+ sorted_transactions.first(10).each do |transaction|
assert_dom "#" + dom_id(transaction), count: 1
end
- end
- test "loads last page when page is out of range" do
- user_oldest_transaction_entry = @user.family.entries.account_transactions.chronological.first
- get transactions_url(page: 9999999999)
+ get transactions_url(page: 2, per_page: 10)
- assert_response :success
- assert_dom "#" + dom_id(user_oldest_transaction_entry), count: 1
+ assert_dom "#" + dom_id(sorted_transactions.last), count: 1
+
+ get transactions_url(page: 9999999, per_page: 10) # out of range loads last page
+
+ assert_dom "#" + dom_id(sorted_transactions.last), count: 1
end
test "can destroy many transactions at once" do
- delete_count = 10
+ transactions = @user.family.entries.account_transactions
+ delete_count = transactions.size
+
assert_difference([ "Account::Transaction.count", "Account::Entry.count" ], -delete_count) do
post bulk_delete_transactions_url, params: {
bulk_delete: {
- entry_ids: @recent_transaction_entries.first(delete_count).pluck(:id)
+ entry_ids: transactions.pluck(:id)
}
}
end
assert_redirected_to transactions_url
- assert_equal "10 transactions deleted", flash[:notice]
+ assert_equal "#{delete_count} transactions deleted", flash[:notice]
end
test "can update many transactions at once" do
- transactions = @user.family.entries.account_transactions.reverse_chronological.limit(20)
-
- transactions.each do |transaction|
- transaction.update! \
- date: Date.current,
- entryable_attributes: {
- id: transaction.account_transaction.id,
- category_id: Category.first.id,
- merchant_id: Merchant.first.id,
- notes: "Starting note"
- }
- end
+ transactions = @user.family.entries.account_transactions
assert_difference [ "Account::Entry.count", "Account::Transaction.count" ], 0 do
post bulk_update_transactions_url, params: {
@@ -173,9 +170,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
assert_redirected_to transactions_url
assert_equal "#{transactions.count} transactions updated", flash[:notice]
- transactions.reload
-
- transactions.each do |transaction|
+ transactions.reload.each do |transaction|
assert_equal 1.day.ago.to_date, transaction.date
assert_equal Category.second, transaction.account_transaction.category
assert_equal Merchant.second, transaction.account_transaction.merchant
diff --git a/test/fixtures/account/balances.yml b/test/fixtures/account/balances.yml
new file mode 100644
index 00000000..ff811a9a
--- /dev/null
+++ b/test/fixtures/account/balances.yml
@@ -0,0 +1,11 @@
+one:
+ date: <%= 2.days.ago.to_date %>
+ balance: 4990
+ currency: USD
+ account: depository
+
+two:
+ date: <%= 1.day.ago.to_date %>
+ balance: 4980
+ currency: USD
+ account: depository
\ No newline at end of file
diff --git a/test/fixtures/account/entries.yml b/test/fixtures/account/entries.yml
index bd45af76..315867aa 100644
--- a/test/fixtures/account/entries.yml
+++ b/test/fixtures/account/entries.yml
@@ -1,323 +1,39 @@
-# Checking account transactions
-checking_one:
+valuation:
+ name: Manual valuation
+ date: <%= 4.days.ago.to_date %>
+ amount: 4995
+ currency: USD
+ account: depository
+ entryable_type: Account::Valuation
+ entryable: one
+
+transaction:
name: Starbucks
- date: <%= 5.days.ago.to_date %>
+ date: <%= 1.day.ago.to_date %>
amount: 10
- account: checking
currency: USD
+ account: depository
entryable_type: Account::Transaction
- entryable: checking_one
+ entryable: one
-checking_two:
- name: Chipotle
- date: <%= 12.days.ago.to_date %>
- amount: 30
- account: checking
- currency: USD
- entryable_type: Account::Transaction
- entryable: checking_two
-
-checking_three:
- name: Amazon
- date: <%= 15.days.ago.to_date %>
- amount: 20
- account: checking
- currency: USD
- entryable_type: Account::Transaction
- entryable: checking_three
-
-checking_four:
- name: Paycheck
- date: <%= 22.days.ago.to_date %>
- amount: -1075
- account: checking
- currency: USD
- entryable_type: Account::Transaction
- entryable: checking_four
-
-checking_five:
- name: Netflix
- date: <%= 29.days.ago.to_date %>
- amount: 15
- account: checking
- currency: USD
- entryable_type: Account::Transaction
- entryable: checking_five
-
-checking_six_payment:
- name: Payment to Credit Card
- date: <%= 29.days.ago.to_date %>
+transfer_out:
+ name: Payment to credit card account
+ date: <%= 3.days.ago.to_date %>
amount: 100
- account: checking
currency: USD
- entryable_type: Account::Transaction
- entryable: checking_six_payment
+ account: depository
marked_as_transfer: true
- transfer: credit_card_payment
-
-checking_seven_transfer:
- name: Transfer to Savings
- date: <%= 30.days.ago.to_date %>
- amount: 250
- account: checking
- currency: USD
- marked_as_transfer: true
- transfer: savings_transfer
+ transfer: one
entryable_type: Account::Transaction
- entryable: checking_seven_transfer
+ entryable: transfer_out
-checking_eight_external_payment:
- name: Transfer TO external CC account (owned by user but not known to app)
- date: <%= 30.days.ago.to_date %>
- amount: 800
- account: checking
- currency: USD
- marked_as_transfer: true
- entryable_type: Account::Transaction
- entryable: checking_eight_external_payment
-
-checking_nine_external_transfer:
- name: Transfer FROM external investing account (owned by user but not known to app)
- date: <%= 31.days.ago.to_date %>
- amount: -200
- account: checking
- currency: USD
- marked_as_transfer: true
- entryable_type: Account::Transaction
- entryable: checking_nine_external_transfer
-
-savings_one:
- name: Interest Received
- date: <%= 5.days.ago.to_date %>
- amount: -200
- account: savings
- currency: USD
- entryable_type: Account::Transaction
- entryable: savings_one
-
-savings_two:
- name: Check Deposit
- date: <%= 12.days.ago.to_date %>
- amount: -50
- account: savings
- currency: USD
- entryable_type: Account::Transaction
- entryable: savings_two
-
-savings_three:
- name: Withdrawal
- date: <%= 18.days.ago.to_date %>
- amount: 2000
- account: savings
- currency: USD
- entryable_type: Account::Transaction
- entryable: savings_three
-
-savings_four:
- name: Check Deposit
- date: <%= 29.days.ago.to_date %>
- amount: -500
- account: savings
- currency: USD
- entryable_type: Account::Transaction
- entryable: savings_four
-
-savings_five_transfer:
- name: Received Transfer from Checking Account
- date: <%= 31.days.ago.to_date %>
- amount: -250
- account: savings
- currency: USD
- marked_as_transfer: true
- transfer: savings_transfer
- entryable_type: Account::Transaction
- entryable: savings_five_transfer
-
-credit_card_one:
- name: Starbucks
- date: <%= 5.days.ago.to_date %>
- amount: 10
- account: credit_card
- currency: USD
- entryable_type: Account::Transaction
- entryable: credit_card_one
-
-credit_card_two:
- name: Chipotle
- date: <%= 12.days.ago.to_date %>
- amount: 30
- account: credit_card
- currency: USD
- entryable_type: Account::Transaction
- entryable: credit_card_two
-
-credit_card_three:
- name: Amazon
- date: <%= 15.days.ago.to_date %>
- amount: 20
- account: credit_card
- currency: USD
- entryable_type: Account::Transaction
- entryable: credit_card_three
-
-credit_card_four_payment:
- name: Received CC Payment from Checking Account
- date: <%= 31.days.ago.to_date %>
+transfer_in:
+ name: Payment received from checking account
+ date: <%= 3.days.ago.to_date %>
amount: -100
+ currency: USD
account: credit_card
- currency: USD
marked_as_transfer: true
- transfer: credit_card_payment
+ transfer: one
entryable_type: Account::Transaction
- entryable: credit_card_four_payment
-
-eur_checking_one:
- name: Check
- date: <%= 9.days.ago.to_date %>
- amount: -50
- currency: EUR
- account: eur_checking
- entryable_type: Account::Transaction
- entryable: eur_checking_one
-
-eur_checking_two:
- name: Shopping trip
- date: <%= 19.days.ago.to_date %>
- amount: 100
- currency: EUR
- account: eur_checking
- entryable_type: Account::Transaction
- entryable: eur_checking_two
-
-eur_checking_three:
- name: Check
- date: <%= 31.days.ago.to_date %>
- amount: -200
- currency: EUR
- account: eur_checking
- entryable_type: Account::Transaction
- entryable: eur_checking_three
-
-multi_currency_one:
- name: Outflow 1
- date: <%= 4.days.ago.to_date %>
- amount: 800
- currency: EUR
- account: multi_currency
- entryable_type: Account::Transaction
- entryable: multi_currency_one
-
-multi_currency_two:
- name: Inflow 1
- date: <%= 9.days.ago.to_date %>
- amount: -50
- currency: USD
- account: multi_currency
- entryable_type: Account::Transaction
- entryable: multi_currency_two
-
-multi_currency_three:
- name: Outflow 2
- date: <%= 19.days.ago.to_date %>
- amount: 110.85
- currency: EUR
- account: multi_currency
- entryable_type: Account::Transaction
- entryable: multi_currency_three
-
-multi_currency_four:
- name: Inflow 2
- date: <%= 29.days.ago.to_date %>
- amount: -200
- currency: USD
- account: multi_currency
- entryable_type: Account::Transaction
- entryable: multi_currency_four
-
-collectable_one_valuation:
- amount: 550
- date: <%= 4.days.ago.to_date %>
- account: collectable
- currency: USD
- entryable_type: Account::Valuation
- entryable: collectable_one
-
-collectable_two_valuation:
- amount: 700
- date: <%= 12.days.ago.to_date %>
- account: collectable
- currency: USD
- entryable_type: Account::Valuation
- entryable: collectable_two
-
-collectable_three_valuation:
- amount: 400
- date: <%= 31.days.ago.to_date %>
- account: collectable
- currency: USD
- entryable_type: Account::Valuation
- entryable: collectable_three
-
-iou_one_valuation:
- amount: 200
- date: <%= 31.days.ago.to_date %>
- account: iou
- currency: USD
- entryable_type: Account::Valuation
- entryable: iou_one
-
-multi_currency_one_valuation:
- amount: 10200
- date: <%= 31.days.ago.to_date %>
- account: multi_currency
- currency: USD
- entryable_type: Account::Valuation
- entryable: multi_currency_one
-
-savings_one_valuation:
- amount: 19500
- date: <%= 12.days.ago.to_date %>
- account: savings
- currency: USD
- entryable_type: Account::Valuation
- entryable: savings_one
-
-savings_two_valuation:
- amount: 21000
- date: <%= 25.days.ago.to_date %>
- account: savings
- currency: USD
- entryable_type: Account::Valuation
- entryable: savings_two
-
-brokerage_one_valuation:
- amount: 10000
- date: <%= 31.days.ago.to_date %>
- account: brokerage
- currency: USD
- entryable_type: Account::Valuation
- entryable: brokerage_one
-
-mortgage_loan_one_valuation:
- amount: 500000
- date: <%= 31.days.ago.to_date %>
- account: mortgage_loan
- currency: USD
- entryable_type: Account::Valuation
- entryable: mortgage_loan_one
-
-house_one_valuation:
- amount: 550000
- date: <%= 31.days.ago.to_date %>
- account: house
- currency: USD
- entryable_type: Account::Valuation
- entryable: house_one
-
-car_one_valuation:
- amount: 18000
- date: <%= 31.days.ago.to_date %>
- account: car
- currency: USD
- entryable_type: Account::Valuation
- entryable: car_one
\ No newline at end of file
+ entryable: transfer_in
diff --git a/test/fixtures/account/syncs.yml b/test/fixtures/account/syncs.yml
new file mode 100644
index 00000000..48c7fc4f
--- /dev/null
+++ b/test/fixtures/account/syncs.yml
@@ -0,0 +1,13 @@
+one:
+ account: depository
+ status: failed
+ start_date: 2024-07-07
+ last_ran_at: 2024-07-07 09:03:31
+ error: test sync error
+ warnings: [ "test warning 1", "test warning 2" ]
+
+two:
+ account: investment
+ status: completed
+ start_date: 2024-07-07
+ last_ran_at: 2024-07-07 09:03:32
diff --git a/test/fixtures/account/transactions.yml b/test/fixtures/account/transactions.yml
index 8e897eb5..426d7d58 100644
--- a/test/fixtures/account/transactions.yml
+++ b/test/fixtures/account/transactions.yml
@@ -1,60 +1,6 @@
-# Checking account transactions
-checking_one:
+one:
category: food_and_drink
-
-checking_two:
- category: food_and_drink
-
-checking_three:
merchant: amazon
-checking_four:
- category: income
-
-checking_five:
- merchant: netflix
-
-checking_six_payment: { }
-
-checking_seven_transfer: { }
-
-checking_eight_external_payment: { }
-
-checking_nine_external_transfer: { }
-
-# Savings account that has transactions and valuation overrides
-savings_one:
- category: income
-
-savings_two:
- category: income
-
-savings_three: { }
-
-savings_four:
- category: income
-
-savings_five_transfer: { }
-
-# Credit card account transactions
-credit_card_one:
- category: food_and_drink
-
-credit_card_two:
- category: food_and_drink
-
-credit_card_three:
- merchant: amazon
-
-credit_card_four_payment: { }
-
-# eur_checking transactions
-eur_checking_one: { }
-eur_checking_two: { }
-eur_checking_three: { }
-
-# multi_currency transactions
-multi_currency_one: { }
-multi_currency_two: { }
-multi_currency_three: { }
-multi_currency_four: { }
+transfer_out: { }
+transfer_in: { }
\ No newline at end of file
diff --git a/test/fixtures/account/transfers.yml b/test/fixtures/account/transfers.yml
index 3c723a8e..6aab7788 100644
--- a/test/fixtures/account/transfers.yml
+++ b/test/fixtures/account/transfers.yml
@@ -1,2 +1 @@
-credit_card_payment: { }
-savings_transfer: { }
+one: { }
diff --git a/test/fixtures/account/valuations.yml b/test/fixtures/account/valuations.yml
index 94e83b2c..21aeae24 100644
--- a/test/fixtures/account/valuations.yml
+++ b/test/fixtures/account/valuations.yml
@@ -1,18 +1,2 @@
-collectable_one: { }
-collectable_two: { }
-collectable_three: { }
-
-iou_one: { }
-
-multi_currency_one: { }
-
-savings_one: { }
-savings_two: { }
-
-brokerage_one: { }
-
-mortgage_loan_one: { }
-
-house_one: { }
-
-car_one: { }
\ No newline at end of file
+one: { }
+two: { }
\ No newline at end of file
diff --git a/test/fixtures/accounts.yml b/test/fixtures/accounts.yml
index 25633c4e..74e09ddb 100644
--- a/test/fixtures/accounts.yml
+++ b/test/fixtures/accounts.yml
@@ -1,31 +1,23 @@
-collectable:
+other_asset:
family: dylan_family
name: Collectable Account
balance: 550
accountable_type: OtherAsset
- accountable: other_asset_collectable
+ accountable: one
-iou:
+other_liability:
family: dylan_family
name: IOU (personal debt to friend)
balance: 200
accountable_type: OtherLiability
- accountable: other_liability_iou
+ accountable: one
-checking:
+depository:
family: dylan_family
name: Checking Account
balance: 5000
accountable_type: Depository
- accountable: depository_checking
- institution: chase
-
-savings:
- family: dylan_family
- name: Savings account
- balance: 19700
- accountable_type: Depository
- accountable: depository_savings
+ accountable: one
institution: chase
credit_card:
@@ -33,56 +25,37 @@ credit_card:
name: Credit Card
balance: 1000
accountable_type: CreditCard
- accountable: credit_one
+ accountable: one
institution: chase
-eur_checking:
- family: dylan_family
- name: Euro Checking Account
- currency: EUR
- balance: 12000
- accountable_type: Depository
- accountable: depository_eur_checking
- institution: revolut
-
-# Multi-currency account (e.g. Wise, Revolut, etc.)
-multi_currency:
- family: dylan_family
- name: Multi Currency Account
- currency: USD # multi-currency accounts still have a "primary" currency
- balance: 9467
- accountable_type: Depository
- accountable: depository_multi_currency
- institution: revolut
-
-brokerage:
+investment:
family: dylan_family
name: Robinhood Brokerage Account
currency: USD
balance: 10000
accountable_type: Investment
- accountable: investment_brokerage
+ accountable: one
-mortgage_loan:
+loan:
family: dylan_family
name: Mortgage Loan
currency: USD
balance: 500000
accountable_type: Loan
- accountable: loan_mortgage
+ accountable: one
-house:
+property:
family: dylan_family
name: 123 Maybe Court
currency: USD
balance: 550000
accountable_type: Property
- accountable: property_house
+ accountable: one
-car:
+vehicle:
family: dylan_family
name: Honda Accord
currency: USD
balance: 18000
accountable_type: Vehicle
- accountable: vehicle_honda_accord
+ accountable: one
diff --git a/test/fixtures/categories.yml b/test/fixtures/categories.yml
index ad3144d8..1c32bf80 100644
--- a/test/fixtures/categories.yml
+++ b/test/fixtures/categories.yml
@@ -1,3 +1,7 @@
+one:
+ name: Test
+ family: empty
+
income:
name: Income
internal_category: income
diff --git a/test/fixtures/credit_cards.yml b/test/fixtures/credit_cards.yml
index 1ad8c478..e0553ab0 100644
--- a/test/fixtures/credit_cards.yml
+++ b/test/fixtures/credit_cards.yml
@@ -1 +1 @@
-credit_one: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/depositories.yml b/test/fixtures/depositories.yml
index ff07aeab..e0553ab0 100644
--- a/test/fixtures/depositories.yml
+++ b/test/fixtures/depositories.yml
@@ -1,4 +1 @@
-depository_checking: { }
-depository_savings: { }
-depository_eur_checking: { }
-depository_multi_currency: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/families.yml b/test/fixtures/families.yml
index 002da9c0..c1b0831a 100644
--- a/test/fixtures/families.yml
+++ b/test/fixtures/families.yml
@@ -1,2 +1,6 @@
+empty:
+ name: Family
+
dylan_family:
name: The Dylan Family
+
diff --git a/test/fixtures/files/expected_family_snapshots.csv b/test/fixtures/files/expected_family_snapshots.csv
deleted file mode 100644
index 62af170c..00000000
--- a/test/fixtures/files/expected_family_snapshots.csv
+++ /dev/null
@@ -1,33 +0,0 @@
-date_offset,collectable,iou,checking,credit_card,savings,eur_checking_eur,eur_checking_usd,multi_currency,brokerage,mortgage_loan,house,car,net_worth,assets,liabilities,depositories,investments,loans,credits,properties,vehicles,other_assets,other_liabilities,spending,income,rolling_spend,rolling_income,savings_rate
-31,400.00,200.00,5150.00,940.00,20950.00,12050.00,13238.13,10200.00,10000.00,500000.00,550000.00,18000.00,126798.13,627938.13,501140.00,49538.13,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,219.72,0.00,0.00,0.0000
-30,400.00,200.00,4100.00,940.00,20950.00,12050.00,13165.83,10200.00,10000.00,500000.00,550000.00,18000.00,125675.83,626815.83,501140.00,48415.83,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,0.00,219.72,1.0000
-29,400.00,200.00,3985.00,940.00,21450.00,12050.00,13182.70,10400.00,10000.00,500000.00,550000.00,18000.00,126277.70,627417.70,501140.00,49017.70,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,15.00,700.00,15.00,919.72,0.9837
-28,400.00,200.00,3985.00,940.00,21450.00,12050.00,13194.75,10400.00,10000.00,500000.00,550000.00,18000.00,126289.75,627429.75,501140.00,49029.75,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-27,400.00,200.00,3985.00,940.00,21450.00,12050.00,13132.09,10400.00,10000.00,500000.00,550000.00,18000.00,126227.09,627367.09,501140.00,48967.09,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-26,400.00,200.00,3985.00,940.00,21450.00,12050.00,13083.89,10400.00,10000.00,500000.00,550000.00,18000.00,126178.89,627318.89,501140.00,48918.89,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-25,400.00,200.00,3985.00,940.00,21000.00,12050.00,13081.48,10400.00,10000.00,500000.00,550000.00,18000.00,125726.48,626866.48,501140.00,48466.48,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-24,400.00,200.00,3985.00,940.00,21000.00,12050.00,13062.20,10400.00,10000.00,500000.00,550000.00,18000.00,125707.20,626847.20,501140.00,48447.20,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-23,400.00,200.00,3985.00,940.00,21000.00,12050.00,13022.44,10400.00,10000.00,500000.00,550000.00,18000.00,125667.44,626807.44,501140.00,48407.44,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,919.72,0.9837
-22,400.00,200.00,5060.00,940.00,21000.00,12050.00,13061.00,10400.00,10000.00,500000.00,550000.00,18000.00,126781.00,627921.00,501140.00,49521.00,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,1075.00,15.00,1994.72,0.9925
-21,400.00,200.00,5060.00,940.00,21000.00,12050.00,13068.23,10400.00,10000.00,500000.00,550000.00,18000.00,126788.23,627928.23,501140.00,49528.23,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,1994.72,0.9925
-20,400.00,200.00,5060.00,940.00,21000.00,12050.00,13079.07,10400.00,10000.00,500000.00,550000.00,18000.00,126799.07,627939.07,501140.00,49539.07,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,15.00,1994.72,0.9925
-19,400.00,200.00,5060.00,940.00,21000.00,11950.00,12932.29,10280.04,10000.00,500000.00,550000.00,18000.00,126532.33,627672.33,501140.00,49272.33,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,228.18,0.00,243.18,1994.72,0.8781
-18,400.00,200.00,5060.00,940.00,19000.00,11950.00,12934.68,10280.04,10000.00,500000.00,550000.00,18000.00,124534.72,625674.72,501140.00,47274.72,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,2000.00,0.00,2243.18,1994.72,-0.1246
-17,400.00,200.00,5060.00,940.00,19000.00,11950.00,12927.51,10280.04,10000.00,500000.00,550000.00,18000.00,124527.55,625667.55,501140.00,47267.55,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,2243.18,1994.72,-0.1246
-16,400.00,200.00,5060.00,940.00,19000.00,11950.00,12916.76,10280.04,10000.00,500000.00,550000.00,18000.00,124516.79,625656.79,501140.00,47256.79,10000.00,500000.00,940.00,550000.00,18000.00,400.00,200.00,0.00,0.00,2243.18,1994.72,-0.1246
-15,400.00,200.00,5040.00,960.00,19000.00,11950.00,12882.10,10280.04,10000.00,500000.00,550000.00,18000.00,124442.14,625602.14,501160.00,47202.14,10000.00,500000.00,960.00,550000.00,18000.00,400.00,200.00,40.00,0.00,2283.18,1994.72,-0.1446
-14,400.00,200.00,5040.00,960.00,19000.00,11950.00,12879.71,10280.04,10000.00,500000.00,550000.00,18000.00,124439.75,625599.75,501160.00,47199.75,10000.00,500000.00,960.00,550000.00,18000.00,400.00,200.00,0.00,0.00,2283.18,1994.72,-0.1446
-13,400.00,200.00,5040.00,960.00,19000.00,11950.00,12873.74,10280.04,10000.00,500000.00,550000.00,18000.00,124433.77,625593.77,501160.00,47193.77,10000.00,500000.00,960.00,550000.00,18000.00,400.00,200.00,0.00,0.00,2283.18,1994.72,-0.1446
-12,700.00,200.00,5010.00,990.00,19500.00,11950.00,12821.16,10280.04,10000.00,500000.00,550000.00,18000.00,125121.19,626311.19,501190.00,47611.19,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,60.00,50.00,2343.18,2044.72,-0.1460
-11,700.00,200.00,5010.00,990.00,19500.00,11950.00,12797.26,10280.04,10000.00,500000.00,550000.00,18000.00,125097.29,626287.29,501190.00,47587.29,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,0.00,2343.18,2044.72,-0.1460
-10,700.00,200.00,5010.00,990.00,19500.00,11950.00,12873.74,10280.04,10000.00,500000.00,550000.00,18000.00,125173.77,626363.77,501190.00,47663.77,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,0.00,2343.18,2044.72,-0.1460
-9,700.00,200.00,5010.00,990.00,19500.00,12000.00,12939.60,10330.04,10000.00,500000.00,550000.00,18000.00,125289.64,626479.64,501190.00,47779.64,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,103.92,2343.18,2148.64,-0.0905
-8,700.00,200.00,5010.00,990.00,19500.00,12000.00,12933.60,10330.04,10000.00,500000.00,550000.00,18000.00,125283.64,626473.64,501190.00,47773.64,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,0.00,2343.18,2148.64,-0.0905
-7,700.00,200.00,5010.00,990.00,19500.00,12000.00,12928.80,10330.04,10000.00,500000.00,550000.00,18000.00,125278.84,626468.84,501190.00,47768.84,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,0.00,2343.18,2148.64,-0.0905
-6,700.00,200.00,5010.00,990.00,19500.00,12000.00,12906.00,10330.04,10000.00,500000.00,550000.00,18000.00,125256.04,626446.04,501190.00,47746.04,10000.00,500000.00,990.00,550000.00,18000.00,700.00,200.00,0.00,0.00,2343.18,2148.64,-0.0905
-5,700.00,200.00,5000.00,1000.00,19700.00,12000.00,12891.60,10330.04,10000.00,500000.00,550000.00,18000.00,125421.64,626621.64,501200.00,47921.64,10000.00,500000.00,1000.00,550000.00,18000.00,700.00,200.00,20.00,200.00,2363.18,2348.64,-0.0062
-4,550.00,200.00,5000.00,1000.00,19700.00,12000.00,12945.60,9467.00,10000.00,500000.00,550000.00,18000.00,124462.60,625662.60,501200.00,47112.60,10000.00,500000.00,1000.00,550000.00,18000.00,550.00,200.00,863.04,0.00,3226.22,2348.64,-0.3737
-3,550.00,200.00,5000.00,1000.00,19700.00,12000.00,13046.40,9467.00,10000.00,500000.00,550000.00,18000.00,124563.40,625763.40,501200.00,47213.40,10000.00,500000.00,1000.00,550000.00,18000.00,550.00,200.00,0.00,0.00,3226.22,2348.64,-0.3737
-2,550.00,200.00,5000.00,1000.00,19700.00,12000.00,12982.80,9467.00,10000.00,500000.00,550000.00,18000.00,124499.80,625699.80,501200.00,47149.80,10000.00,500000.00,1000.00,550000.00,18000.00,550.00,200.00,0.00,0.00,3226.22,2348.64,-0.3737
-1,550.00,200.00,5000.00,1000.00,19700.00,12000.00,13014.00,9467.00,10000.00,500000.00,550000.00,18000.00,124531.00,625731.00,501200.00,47181.00,10000.00,500000.00,1000.00,550000.00,18000.00,550.00,200.00,0.00,0.00,3226.22,2348.64,-0.3737
-0,550.00,200.00,5000.00,1000.00,19700.00,12000.00,13000.80,9467.00,10000.00,500000.00,550000.00,18000.00,124517.80,625717.80,501200.00,47167.80,10000.00,500000.00,1000.00,550000.00,18000.00,550.00,200.00,0.00,0.00,3226.22,2348.64,-0.3737
\ No newline at end of file
diff --git a/test/fixtures/imports.yml b/test/fixtures/imports.yml
index 0b7d1959..4ab16a08 100644
--- a/test/fixtures/imports.yml
+++ b/test/fixtures/imports.yml
@@ -1,9 +1,9 @@
empty_import:
- account: checking
+ account: depository
created_at: <%= 1.minute.ago %>
completed_import:
- account: checking
+ account: depository
column_mappings:
date: date
name: name
diff --git a/test/fixtures/investments.yml b/test/fixtures/investments.yml
index 10ecb60d..e0553ab0 100644
--- a/test/fixtures/investments.yml
+++ b/test/fixtures/investments.yml
@@ -1 +1 @@
-investment_brokerage: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/loans.yml b/test/fixtures/loans.yml
index 6043e466..e0553ab0 100644
--- a/test/fixtures/loans.yml
+++ b/test/fixtures/loans.yml
@@ -1 +1 @@
-loan_mortgage: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/merchants.yml b/test/fixtures/merchants.yml
index ade78c09..3e3ca05a 100644
--- a/test/fixtures/merchants.yml
+++ b/test/fixtures/merchants.yml
@@ -1,3 +1,7 @@
+one:
+ name: Test
+ family: empty
+
netflix:
name: Netflix
color: "#fd7f6f"
diff --git a/test/fixtures/other_assets.yml b/test/fixtures/other_assets.yml
index 74674e8c..09e7865d 100644
--- a/test/fixtures/other_assets.yml
+++ b/test/fixtures/other_assets.yml
@@ -1,3 +1,2 @@
-other_asset_collectable: { }
-
+one: { }
diff --git a/test/fixtures/other_liabilities.yml b/test/fixtures/other_liabilities.yml
index 08028f97..e0553ab0 100644
--- a/test/fixtures/other_liabilities.yml
+++ b/test/fixtures/other_liabilities.yml
@@ -1 +1 @@
-other_asset_iou: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/properties.yml b/test/fixtures/properties.yml
index c6026df2..e0553ab0 100644
--- a/test/fixtures/properties.yml
+++ b/test/fixtures/properties.yml
@@ -1 +1 @@
-property_house: { }
+one: { }
\ No newline at end of file
diff --git a/test/fixtures/taggings.yml b/test/fixtures/taggings.yml
index caefa609..5039ba27 100644
--- a/test/fixtures/taggings.yml
+++ b/test/fixtures/taggings.yml
@@ -1,10 +1,10 @@
one:
- tag: hawaii_trip
- taggable: checking_one
+ tag: one
+ taggable: one
taggable_type: Account::Transaction
two:
- tag: emergency_fund
- taggable: checking_two
+ tag: two
+ taggable: one
taggable_type: Account::Transaction
diff --git a/test/fixtures/tags.yml b/test/fixtures/tags.yml
index 600a7fd1..1c76d6cc 100644
--- a/test/fixtures/tags.yml
+++ b/test/fixtures/tags.yml
@@ -1,11 +1,11 @@
-trips:
+one:
name: Trips
family: dylan_family
-hawaii_trip:
- name: Hawaii Trip
+two:
+ name: Emergency fund
family: dylan_family
-emergency_fund:
- name: Emergency Fund
- family: dylan_family
+three:
+ name: Test
+ family: empty
\ No newline at end of file
diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml
index a78a3942..3c9aa4ed 100644
--- a/test/fixtures/users.yml
+++ b/test/fixtures/users.yml
@@ -1,3 +1,10 @@
+empty:
+ family: empty
+ first_name: User
+ last_name: One
+ email: user1@email.com
+ password_digest: <%= BCrypt::Password.create('password') %>
+
family_admin:
family: dylan_family
first_name: Bob
diff --git a/test/fixtures/vehicles.yml b/test/fixtures/vehicles.yml
index a0ea340e..e0553ab0 100644
--- a/test/fixtures/vehicles.yml
+++ b/test/fixtures/vehicles.yml
@@ -1 +1 @@
-vehicle_honda_accord: { }
+one: { }
\ No newline at end of file
diff --git a/test/models/account/balance/calculator_test.rb b/test/models/account/balance/calculator_test.rb
deleted file mode 100644
index bac5d4c3..00000000
--- a/test/models/account/balance/calculator_test.rb
+++ /dev/null
@@ -1,101 +0,0 @@
-require "test_helper"
-require "csv"
-
-class Account::Balance::CalculatorTest < ActiveSupport::TestCase
- include FamilySnapshotTestHelper
-
- test "syncs other asset balances" do
- expected_balances = get_expected_balances_for(:collectable)
- assert_account_balances calculated_balances_for(:collectable), expected_balances
- end
-
- test "syncs other liability balances" do
- expected_balances = get_expected_balances_for(:iou)
- assert_account_balances calculated_balances_for(:iou), expected_balances
- end
-
- test "syncs credit balances" do
- expected_balances = get_expected_balances_for :credit_card
- assert_account_balances calculated_balances_for(:credit_card), expected_balances
- end
-
- test "syncs checking account balances" do
- expected_balances = get_expected_balances_for(:checking)
- assert_account_balances calculated_balances_for(:checking), expected_balances
- end
-
- test "syncs foreign checking account balances" do
- required_exchange_rates_for_sync = [
- 1.0834, 1.0845, 1.0819, 1.0872, 1.0788, 1.0743, 1.0755, 1.0774,
- 1.0778, 1.0783, 1.0773, 1.0709, 1.0729, 1.0773, 1.0778, 1.078,
- 1.0809, 1.0818, 1.0824, 1.0822, 1.0854, 1.0845, 1.0839, 1.0807,
- 1.084, 1.0856, 1.0858, 1.0898, 1.095, 1.094, 1.0926, 1.0986
- ]
-
- required_exchange_rates_for_sync.each_with_index do |exchange_rate, idx|
- ExchangeRate.create! date: idx.days.ago.to_date, from_currency: "EUR", to_currency: "USD", rate: exchange_rate
- end
-
- # Foreign accounts will generate balances for all currencies
- expected_usd_balances = get_expected_balances_for(:eur_checking_usd)
- expected_eur_balances = get_expected_balances_for(:eur_checking_eur)
-
- calculated_balances = calculated_balances_for(:eur_checking)
- calculated_usd_balances = calculated_balances.select { |b| b[:currency] == "USD" }
- calculated_eur_balances = calculated_balances.select { |b| b[:currency] == "EUR" }
-
- assert_account_balances calculated_usd_balances, expected_usd_balances
- assert_account_balances calculated_eur_balances, expected_eur_balances
- end
-
- test "syncs multi-currency checking account balances" do
- required_exchange_rates_for_sync = [
- { from_currency: "EUR", to_currency: "USD", date: 4.days.ago.to_date, rate: 1.0788 },
- { from_currency: "EUR", to_currency: "USD", date: 19.days.ago.to_date, rate: 1.0822 }
- ]
-
- ExchangeRate.insert_all(required_exchange_rates_for_sync)
-
- expected_balances = get_expected_balances_for(:multi_currency)
- assert_account_balances calculated_balances_for(:multi_currency), expected_balances
- end
-
- test "syncs savings accounts balances" do
- expected_balances = get_expected_balances_for(:savings)
- assert_account_balances calculated_balances_for(:savings), expected_balances
- end
-
- test "syncs investment account balances" do
- expected_balances = get_expected_balances_for(:brokerage)
- assert_account_balances calculated_balances_for(:brokerage), expected_balances
- end
-
- test "syncs loan account balances" do
- expected_balances = get_expected_balances_for(:mortgage_loan)
- assert_account_balances calculated_balances_for(:mortgage_loan), expected_balances
- end
-
- test "syncs property account balances" do
- expected_balances = get_expected_balances_for(:house)
- assert_account_balances calculated_balances_for(:house), expected_balances
- end
-
- test "syncs vehicle account balances" do
- expected_balances = get_expected_balances_for(:car)
- assert_account_balances calculated_balances_for(:car), expected_balances
- end
-
- private
- def assert_account_balances(actual_balances, expected_balances)
- assert_equal expected_balances.count, actual_balances.count
-
- actual_balances.each do |ab|
- expected_balance = expected_balances.find { |eb| eb[:date] == ab[:date] }
- assert_in_delta expected_balance[:balance], ab[:balance], 0.01, "Balance incorrect on date: #{ab[:date]}"
- end
- end
-
- def calculated_balances_for(account_key)
- Account::Balance::Calculator.new(accounts(account_key)).daily_balances
- end
-end
diff --git a/test/models/account/balance/syncer_test.rb b/test/models/account/balance/syncer_test.rb
new file mode 100644
index 00000000..c70f52e9
--- /dev/null
+++ b/test/models/account/balance/syncer_test.rb
@@ -0,0 +1,133 @@
+require "test_helper"
+
+class Account::Balance::SyncerTest < ActiveSupport::TestCase
+ include Account::EntriesTestHelper
+
+ setup do
+ @account = families(:empty).accounts.create!(name: "Test", balance: 20000, currency: "USD", accountable: Depository.new)
+ end
+
+ test "syncs account with no entries" do
+ assert_equal 0, @account.balances.count
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "syncs account with valuations only" do
+ create_valuation(account: @account, date: 2.days.ago.to_date, amount: 22000)
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ 22000, 22000, @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "syncs account with transactions only" do
+ create_transaction(account: @account, date: 4.days.ago.to_date, amount: 100)
+ create_transaction(account: @account, date: 2.days.ago.to_date, amount: -500)
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ 19600, 19500, 19500, 20000, 20000, @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "syncs account with valuations and transactions" do
+ create_valuation(account: @account, date: 5.days.ago.to_date, amount: 20000)
+ create_transaction(account: @account, date: 3.days.ago.to_date, amount: -500)
+ create_transaction(account: @account, date: 2.days.ago.to_date, amount: 100)
+ create_valuation(account: @account, date: 1.day.ago.to_date, amount: 25000)
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ 20000, 20000, 20500, 20400, 25000, @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "syncs account with transactions in multiple currencies" do
+ ExchangeRate.create! date: 1.day.ago.to_date, from_currency: "EUR", to_currency: "USD", rate: 1.2
+
+ create_transaction(account: @account, date: 3.days.ago.to_date, amount: 100, currency: "USD")
+ create_transaction(account: @account, date: 2.days.ago.to_date, amount: 300, currency: "USD")
+ create_transaction(account: @account, date: 1.day.ago.to_date, amount: 500, currency: "EUR") # €500 * 1.2 = $600
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ 21000, 20900, 20600, 20000, @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "converts foreign account balances to family currency" do
+ @account.update! currency: "EUR"
+
+ create_transaction(date: 1.day.ago.to_date, amount: 1000, account: @account, currency: "EUR")
+
+ create_exchange_rate(2.days.ago.to_date, from: "EUR", to: "USD", rate: 2)
+ create_exchange_rate(1.day.ago.to_date, from: "EUR", to: "USD", rate: 2)
+ create_exchange_rate(Date.current, from: "EUR", to: "USD", rate: 2)
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ usd_balances = @account.balances.where(currency: "USD").chronological.map(&:balance)
+ eur_balances = @account.balances.where(currency: "EUR").chronological.map(&:balance)
+
+ assert_equal [ 21000, 20000, @account.balance ], eur_balances # native account balances
+ assert_equal [ 42000, 40000, @account.balance * 2 ], usd_balances # converted balances at rate of 2:1
+ end
+
+ test "fails with error if exchange rate not available for any entry" do
+ create_transaction(account: @account, currency: "EUR")
+
+ syncer = Account::Balance::Syncer.new(@account)
+
+ assert_raises Money::ConversionError do
+ syncer.run
+ end
+ end
+
+ # Account is able to calculate balances in its own currency (i.e. can still show a historical graph), but
+ # doesn't have exchange rates available to convert those calculated balances to the family currency
+ test "completes with warning if exchange rates not available to convert to family currency" do
+ @account.update! currency: "EUR"
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal 1, syncer.warnings.count
+ end
+
+ test "overwrites existing balances and purges stale balances" do
+ assert_equal 0, @account.balances.size
+
+ @account.balances.create! date: Date.current, currency: "USD", balance: 30000 # incorrect balance, will be updated
+ @account.balances.create! date: 10.years.ago.to_date, currency: "USD", balance: 35000 # Out of range balance, will be deleted
+
+ assert_equal 2, @account.balances.size
+
+ syncer = Account::Balance::Syncer.new(@account)
+ syncer.run
+
+ assert_equal [ @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ test "partial sync does not affect balances prior to sync start date" do
+ existing_balance = @account.balances.create! date: 2.days.ago.to_date, currency: "USD", balance: 30000
+
+ transaction = create_transaction(account: @account, date: 1.day.ago.to_date, amount: 100, currency: "USD")
+
+ syncer = Account::Balance::Syncer.new(@account, start_date: 1.day.ago.to_date)
+ syncer.run
+
+ assert_equal [ existing_balance.balance, existing_balance.balance - transaction.amount, @account.balance ], @account.balances.chronological.map(&:balance)
+ end
+
+ private
+
+ def create_exchange_rate(date, from:, to:, rate:)
+ ExchangeRate.create! date: date, from_currency: from, to_currency: to, rate: rate
+ end
+end
diff --git a/test/models/account/entry_test.rb b/test/models/account/entry_test.rb
index 25c6a09c..edea8464 100644
--- a/test/models/account/entry_test.rb
+++ b/test/models/account/entry_test.rb
@@ -1,26 +1,29 @@
require "test_helper"
class Account::EntryTest < ActiveSupport::TestCase
+ include Account::EntriesTestHelper
+
setup do
- @entry = account_entries :checking_one
- @family = families :dylan_family
+ @entry = account_entries :transaction
end
test "valuations cannot have more than one entry per day" do
- new_entry = Account::Entry.new \
- entryable: Account::Valuation.new,
- date: @entry.date, # invalid
- currency: @entry.currency,
- amount: @entry.amount
+ existing_valuation = account_entries :valuation
- assert new_entry.invalid?
+ new_valuation = Account::Entry.new \
+ entryable: Account::Valuation.new,
+ date: existing_valuation.date, # invalid
+ currency: existing_valuation.currency,
+ amount: existing_valuation.amount
+
+ assert new_valuation.invalid?
end
test "triggers sync with correct start date when transaction is set to prior date" do
prior_date = @entry.date - 1
@entry.update! date: prior_date
- @entry.account.expects(:sync_later).with(prior_date)
+ @entry.account.expects(:sync_later).with(start_date: prior_date)
@entry.sync_account_later
end
@@ -28,48 +31,62 @@ class Account::EntryTest < ActiveSupport::TestCase
prior_date = @entry.date
@entry.update! date: @entry.date + 1
- @entry.account.expects(:sync_later).with(prior_date)
+ @entry.account.expects(:sync_later).with(start_date: prior_date)
@entry.sync_account_later
end
test "triggers sync with correct start date when transaction deleted" do
- prior_entry = account_entries(:checking_two) # 12 days ago
- current_entry = account_entries(:checking_one) # 5 days ago
+ current_entry = create_transaction(date: 1.day.ago.to_date)
+ prior_entry = create_transaction(date: current_entry.date - 1.day)
+
current_entry.destroy!
- current_entry.account.expects(:sync_later).with(prior_entry.date)
+ current_entry.account.expects(:sync_later).with(start_date: prior_entry.date)
current_entry.sync_account_later
end
test "can search entries" do
+ family = families(:empty)
+ account = family.accounts.create! name: "Test", balance: 0, accountable: Depository.new
+ category = family.categories.first
+ merchant = family.merchants.first
+
+ create_transaction(account: account, name: "a transaction")
+ create_transaction(account: account, name: "ignored")
+ create_transaction(account: account, name: "third transaction", category: category, merchant: merchant)
+
params = { search: "a" }
- assert_equal 12, Account::Entry.search(params).size
+ assert_equal 2, family.entries.search(params).size
- params = params.merge(categories: [ "Food & Drink" ]) # transaction specific search param
+ params = params.merge(categories: [ category.name ], merchants: [ merchant.name ]) # transaction specific search param
- assert_equal 2, Account::Entry.search(params).size
+ assert_equal 1, family.entries.search(params).size
end
test "can calculate total spending for a group of transactions" do
- assert_equal Money.new(2135), @family.entries.expense_total("USD")
- assert_equal Money.new(1010.85, "EUR"), @family.entries.expense_total("EUR")
+ family = families(:empty)
+ account = family.accounts.create! name: "Test", balance: 0, accountable: Depository.new
+ create_transaction(account: account, amount: 100)
+ create_transaction(account: account, amount: 100)
+ create_transaction(account: account, amount: -500) # income, will be ignored
+
+ assert_equal Money.new(200), family.entries.expense_total("USD")
end
test "can calculate total income for a group of transactions" do
- assert_equal -Money.new(2075), @family.entries.income_total("USD")
- assert_equal -Money.new(250, "EUR"), @family.entries.income_total("EUR")
+ family = families(:empty)
+ account = family.accounts.create! name: "Test", balance: 0, accountable: Depository.new
+ create_transaction(account: account, amount: -100)
+ create_transaction(account: account, amount: -100)
+ create_transaction(account: account, amount: 500) # income, will be ignored
+
+ assert_equal Money.new(-200), family.entries.income_total("USD")
end
# See: https://github.com/maybe-finance/maybe/wiki/vision#signage-of-money
test "transactions with negative amounts are inflows, positive amounts are outflows to an account" do
- inflow_transaction = account_entries(:checking_four)
- outflow_transaction = account_entries(:checking_five)
-
- assert inflow_transaction.amount < 0
- assert inflow_transaction.inflow?
-
- assert outflow_transaction.amount >= 0
- assert outflow_transaction.outflow?
+ assert create_transaction(amount: -10).inflow?
+ assert create_transaction(amount: 10).outflow?
end
end
diff --git a/test/models/account/sync_test.rb b/test/models/account/sync_test.rb
new file mode 100644
index 00000000..335dabe9
--- /dev/null
+++ b/test/models/account/sync_test.rb
@@ -0,0 +1,36 @@
+require "test_helper"
+
+class Account::SyncTest < ActiveSupport::TestCase
+ setup do
+ @account = accounts(:depository)
+
+ @sync = Account::Sync.for(@account)
+ @balance_syncer = mock("Account::Balance::Syncer")
+ Account::Balance::Syncer.expects(:new).with(@account, start_date: nil).returns(@balance_syncer).once
+ end
+
+ test "runs sync" do
+ @balance_syncer.expects(:run).once
+ @balance_syncer.expects(:warnings).returns([ "test sync warning" ]).once
+
+ assert_equal "pending", @sync.status
+ assert_equal [], @sync.warnings
+ assert_nil @sync.last_ran_at
+
+ @sync.run
+
+ assert_equal "completed", @sync.status
+ assert_equal [ "test sync warning" ], @sync.warnings
+ assert @sync.last_ran_at
+ end
+
+ test "handles sync errors" do
+ @balance_syncer.expects(:run).raises(StandardError.new("test sync error"))
+
+ @sync.run
+
+ assert @sync.last_ran_at
+ assert_equal "failed", @sync.status
+ assert_equal "test sync error", @sync.error
+ end
+end
diff --git a/test/models/account/syncable_test.rb b/test/models/account/syncable_test.rb
deleted file mode 100644
index 6eb8c808..00000000
--- a/test/models/account/syncable_test.rb
+++ /dev/null
@@ -1,124 +0,0 @@
-require "test_helper"
-
-class Account::SyncableTest < ActiveSupport::TestCase
- include ActiveJob::TestHelper
-
- setup do
- @account = accounts(:savings)
- end
-
- test "calculates effective start date of an account" do
- assert_equal 31.days.ago.to_date, accounts(:collectable).effective_start_date
- assert_equal 31.days.ago.to_date, @account.effective_start_date
- end
-
- test "syncs regular account" do
- @account.sync
- assert_equal "ok", @account.status
- assert_equal 32, @account.balances.count
- end
-
- test "syncs multi currency account" do
- required_exchange_rates_for_sync = [
- { from_currency: "EUR", to_currency: "USD", date: 4.days.ago.to_date, rate: 1.0788 },
- { from_currency: "EUR", to_currency: "USD", date: 19.days.ago.to_date, rate: 1.0822 }
- ]
-
- ExchangeRate.insert_all(required_exchange_rates_for_sync)
-
- account = accounts(:multi_currency)
- account.sync
- assert_equal "ok", account.status
- assert_equal 32, account.balances.where(currency: "USD").count
- end
-
- test "triggers sync job" do
- assert_enqueued_with(job: AccountSyncJob, args: [ @account, Date.current ]) do
- @account.sync_later(Date.current)
- end
- end
-
- test "account has no balances until synced" do
- account = accounts(:savings)
-
- assert_equal 0, account.balances.count
- end
-
- test "account has balances after syncing" do
- account = accounts(:savings)
- account.sync
-
- assert_equal 32, account.balances.count
- end
-
- test "partial sync with missing historical balances performs a full sync" do
- account = accounts(:savings)
- account.sync 10.days.ago.to_date
-
- assert_equal 32, account.balances.count
- end
-
- test "balances are updated after syncing" do
- account = accounts(:savings)
- balance_date = 10.days.ago
- account.balances.create!(date: balance_date, balance: 1000)
- account.sync
-
- assert_equal 19500, account.balances.find_by(date: balance_date)[:balance]
- end
-
- test "can perform a partial sync with a given sync start date" do
- # Perform a full sync to populate all balances
- @account.sync
-
- # Perform partial sync
- sync_start_date = 5.days.ago.to_date
- balances_before_sync = @account.balances.to_a
- @account.sync sync_start_date
- balances_after_sync = @account.reload.balances.to_a
-
- # Balances on or after should be updated
- balances_after_sync.each do |balance_after_sync|
- balance_before_sync = balances_before_sync.find { |b| b.date == balance_after_sync.date }
-
- if balance_after_sync.date >= sync_start_date
- assert balance_before_sync.updated_at < balance_after_sync.updated_at
- else
- assert_equal balance_before_sync.updated_at, balance_after_sync.updated_at
- end
- end
- end
-
- test "foreign currency account has balances in each currency after syncing" do
- required_exchange_rates_for_sync = [
- 1.0834, 1.0845, 1.0819, 1.0872, 1.0788, 1.0743, 1.0755, 1.0774,
- 1.0778, 1.0783, 1.0773, 1.0709, 1.0729, 1.0773, 1.0778, 1.078,
- 1.0809, 1.0818, 1.0824, 1.0822, 1.0854, 1.0845, 1.0839, 1.0807,
- 1.084, 1.0856, 1.0858, 1.0898, 1.095, 1.094, 1.0926, 1.0986
- ]
-
- required_exchange_rates_for_sync.each_with_index do |exchange_rate, idx|
- ExchangeRate.create! date: idx.days.ago.to_date, from_currency: "EUR", to_currency: "USD", rate: exchange_rate
- end
-
- account = accounts(:eur_checking)
- account.sync
-
- assert_equal 64, account.balances.count
- assert_equal 32, account.balances.where(currency: "EUR").count
- assert_equal 32, account.balances.where(currency: "USD").count
- end
-
- test "stale balances are purged after syncing" do
- account = accounts(:savings)
-
- # Create old, stale balances that should be purged (since they are before account start date)
- account.balances.create!(date: 1.year.ago, balance: 1000)
- account.balances.create!(date: 2.years.ago, balance: 2000)
- account.balances.create!(date: 3.years.ago, balance: 3000)
-
- account.sync
-
- assert_equal 32, account.balances.count
- end
-end
diff --git a/test/models/account/transfer_test.rb b/test/models/account/transfer_test.rb
index 8c380c0d..2c9265c6 100644
--- a/test/models/account/transfer_test.rb
+++ b/test/models/account/transfer_test.rb
@@ -2,22 +2,8 @@ require "test_helper"
class Account::TransferTest < ActiveSupport::TestCase
setup do
- # Transfers can be posted on different dates
- @outflow = accounts(:checking).entries.create! \
- date: 1.day.ago.to_date,
- name: "Transfer to Savings",
- amount: 100,
- currency: "USD",
- marked_as_transfer: true,
- entryable: Account::Transaction.new
-
- @inflow = accounts(:savings).entries.create! \
- date: Date.current,
- name: "Transfer from Savings",
- amount: -100,
- currency: "USD",
- marked_as_transfer: true,
- entryable: Account::Transaction.new
+ @outflow = account_entries(:transfer_out)
+ @inflow = account_entries(:transfer_in)
end
test "transfer valid if it has inflow and outflow from different accounts for the same amount" do
@@ -28,14 +14,15 @@ class Account::TransferTest < ActiveSupport::TestCase
test "transfer must have 2 transactions" do
invalid_transfer_1 = Account::Transfer.new entries: [ @outflow ]
- invalid_transfer_2 = Account::Transfer.new entries: [ @inflow, @outflow, account_entries(:savings_four) ]
+ invalid_transfer_2 = Account::Transfer.new entries: [ @inflow, @outflow, account_entries(:transaction) ]
assert invalid_transfer_1.invalid?
assert invalid_transfer_2.invalid?
end
test "transfer cannot have 2 transactions from the same account" do
- account = accounts(:checking)
+ account = accounts(:depository)
+
inflow = account.entries.create! \
date: Date.current,
name: "Inflow",
diff --git a/test/models/account_test.rb b/test/models/account_test.rb
index 472ff059..b0c45a7d 100644
--- a/test/models/account_test.rb
+++ b/test/models/account_test.rb
@@ -1,38 +1,31 @@
require "test_helper"
-require "csv"
class AccountTest < ActiveSupport::TestCase
- def setup
- @account = accounts(:checking)
+ include ActiveJob::TestHelper
+
+ setup do
+ @account = accounts(:depository)
@family = families(:dylan_family)
end
- test "recognizes foreign currency account" do
- regular_account = accounts(:checking)
- foreign_account = accounts(:eur_checking)
- assert_not regular_account.foreign_currency?
- assert foreign_account.foreign_currency?
+ test "can sync later" do
+ assert_enqueued_with(job: AccountSyncJob, args: [ @account, start_date: Date.current ]) do
+ @account.sync_later start_date: Date.current
+ end
end
- test "recognizes multi currency account" do
- regular_account = accounts(:checking)
- multi_currency_account = accounts(:multi_currency)
- assert_not regular_account.multi_currency?
- assert multi_currency_account.multi_currency?
- end
+ test "can sync" do
+ start_date = 10.days.ago.to_date
- test "multi currency and foreign currency are different concepts" do
- multi_currency_account = accounts(:multi_currency)
- assert_equal multi_currency_account.family.currency, multi_currency_account.currency
- assert multi_currency_account.multi_currency?
- assert_not multi_currency_account.foreign_currency?
+ mock_sync = mock("Account::Sync")
+ mock_sync.expects(:run).once
+
+ Account::Sync.expects(:for).with(@account, start_date: start_date).returns(mock_sync).once
+
+ @account.sync start_date: start_date
end
test "groups accounts by type" do
- @family.accounts.each do |account|
- account.sync
- end
-
result = @family.accounts.by_group(period: Period.all)
assets = result[:assets]
liabilities = result[:liabilities]
@@ -50,7 +43,7 @@ class AccountTest < ActiveSupport::TestCase
loans = liabilities.children.find { |group| group.name == "Loan" }
other_liabilities = liabilities.children.find { |group| group.name == "OtherLiability" }
- assert_equal 4, depositories.children.count
+ assert_equal 1, depositories.children.count
assert_equal 1, properties.children.count
assert_equal 1, vehicles.children.count
assert_equal 1, investments.children.count
@@ -61,38 +54,24 @@ class AccountTest < ActiveSupport::TestCase
assert_equal 1, other_liabilities.children.count
end
- test "generates series with last balance equal to current account balance" do
- # If account hasn't been synced, series falls back to a single point with the current balance
- assert_equal @account.balance_money, @account.series.last.value
-
- @account.sync
-
- # Synced series will always have final balance equal to the current account balance
- assert_equal @account.balance_money, @account.series.last.value
+ test "generates balance series" do
+ assert_equal 2, @account.series.values.count
end
- test "generates empty series for foreign currency if no exchange rate" do
- account = accounts(:eur_checking)
-
- # We know EUR -> NZD exchange rate is not available in fixtures
- assert_equal 0, account.series(currency: "NZD").values.count
+ test "generates balance series with single value if no balances" do
+ @account.balances.delete_all
+ assert_equal 1, @account.series.values.count
end
- test "should destroy dependent transactions" do
- assert_difference("Account::Transaction.count", -@account.transactions.count) do
- @account.destroy
- end
+ test "generates balance series in period" do
+ @account.balances.delete_all
+ @account.balances.create! date: 31.days.ago.to_date, balance: 5000, currency: "USD" # out of period range
+ @account.balances.create! date: 30.days.ago.to_date, balance: 5000, currency: "USD" # in range
+
+ assert_equal 1, @account.series(period: Period.last_30_days).values.count
end
- test "should destroy dependent balances" do
- assert_difference("Account::Balance.count", -@account.balances.count) do
- @account.destroy
- end
- end
-
- test "should destroy dependent valuations" do
- assert_difference("Account::Valuation.count", -@account.valuations.count) do
- @account.destroy
- end
+ test "generates empty series if no balances and no exchange rate" do
+ assert_equal 0, @account.series(currency: "NZD").values.count
end
end
diff --git a/test/models/category_test.rb b/test/models/category_test.rb
index 4020747b..b7e60b20 100644
--- a/test/models/category_test.rb
+++ b/test/models/category_test.rb
@@ -20,7 +20,7 @@ class CategoryTest < ActiveSupport::TestCase
end
test "updating name should clear the internal_category field" do
- category = Category.take
+ category = categories(:income)
assert_changes "category.reload.internal_category", to: nil do
category.update_attribute(:name, "new name")
end
diff --git a/test/models/family_test.rb b/test/models/family_test.rb
index 9efc06ed..de4b4b55 100644
--- a/test/models/family_test.rb
+++ b/test/models/family_test.rb
@@ -2,144 +2,148 @@ require "test_helper"
require "csv"
class FamilyTest < ActiveSupport::TestCase
- include FamilySnapshotTestHelper
+ include Account::EntriesTestHelper
def setup
- @family = families(:dylan_family)
-
- required_exchange_rates_for_family = [
- 1.0834, 1.0845, 1.0819, 1.0872, 1.0788, 1.0743, 1.0755, 1.0774,
- 1.0778, 1.0783, 1.0773, 1.0709, 1.0729, 1.0773, 1.0778, 1.078,
- 1.0809, 1.0818, 1.0824, 1.0822, 1.0854, 1.0845, 1.0839, 1.0807,
- 1.084, 1.0856, 1.0858, 1.0898, 1.095, 1.094, 1.0926, 1.0986
- ]
-
- required_exchange_rates_for_family.each_with_index do |exchange_rate, idx|
- ExchangeRate.create! date: idx.days.ago.to_date, from_currency: "EUR", to_currency: "USD", rate: exchange_rate
- end
-
- @family.accounts.each do |account|
- account.sync
- end
+ @family = families :empty
end
- test "should have many users" do
- assert @family.users.size > 0
- assert @family.users.include?(users(:family_admin))
+ test "calculates assets" do
+ assert_equal Money.new(0, @family.currency), @family.assets
+
+ @family.accounts.create!(balance: 1000, accountable: Depository.new)
+ @family.accounts.create!(balance: 5000, accountable: OtherAsset.new)
+ @family.accounts.create!(balance: 10000, accountable: CreditCard.new) # ignored
+
+ assert_equal Money.new(1000 + 5000, @family.currency), @family.assets
end
- test "should have many accounts" do
- assert @family.accounts.size > 0
+ test "calculates liabilities" do
+ assert_equal Money.new(0, @family.currency), @family.liabilities
+
+ @family.accounts.create!(balance: 1000, accountable: CreditCard.new)
+ @family.accounts.create!(balance: 5000, accountable: OtherLiability.new)
+ @family.accounts.create!(balance: 10000, accountable: Depository.new) # ignored
+
+ assert_equal Money.new(1000 + 5000, @family.currency), @family.liabilities
end
- test "should destroy dependent users" do
- assert_difference("User.count", -@family.users.count) do
- @family.destroy
- end
- end
+ test "calculates net worth" do
+ assert_equal Money.new(0, @family.currency), @family.net_worth
- test "should destroy dependent accounts" do
- assert_difference("Account.count", -@family.accounts.count) do
- @family.destroy
- end
- end
+ @family.accounts.create!(balance: 1000, accountable: CreditCard.new)
+ @family.accounts.create!(balance: 50000, accountable: Depository.new)
- test "should destroy dependent transaction categories" do
- assert_difference("Category.count", -@family.categories.count) do
- @family.destroy
- end
- end
-
- test "should destroy dependent merchants" do
- assert_difference("Merchant.count", -@family.merchants.count) do
- @family.destroy
- end
- end
-
- test "should calculate total assets" do
- expected = get_today_snapshot_value_for :assets
- assert_in_delta expected, @family.assets.amount, 0.01
- end
-
- test "should calculate total liabilities" do
- expected = get_today_snapshot_value_for :liabilities
- assert_in_delta expected, @family.liabilities.amount, 0.01
- end
-
- test "should calculate net worth" do
- expected = get_today_snapshot_value_for :net_worth
- assert_in_delta expected, @family.net_worth.amount, 0.01
- end
-
- test "calculates asset time series" do
- series = @family.snapshot[:asset_series]
- expected_series = get_expected_balances_for :assets
-
- assert_time_series_balances series, expected_series
- end
-
- test "calculates liability time series" do
- series = @family.snapshot[:liability_series]
- expected_series = get_expected_balances_for :liabilities
-
- assert_time_series_balances series, expected_series
- end
-
- test "calculates net worth time series" do
- series = @family.snapshot[:net_worth_series]
- expected_series = get_expected_balances_for :net_worth
-
- assert_time_series_balances series, expected_series
- end
-
- test "calculates rolling expenses" do
- series = @family.snapshot_transactions[:spending_series]
- expected_series = get_expected_balances_for :rolling_spend
-
- assert_time_series_balances series, expected_series, ignore_count: true
- end
-
- test "calculates rolling income" do
- series = @family.snapshot_transactions[:income_series]
- expected_series = get_expected_balances_for :rolling_income
-
- assert_time_series_balances series, expected_series, ignore_count: true
- end
-
- test "calculates savings rate series" do
- series = @family.snapshot_transactions[:savings_rate_series]
- expected_series = get_expected_balances_for :savings_rate
-
- series.values.each do |tsb|
- expected_balance = expected_series.find { |eb| eb[:date] == tsb.date }
- assert_in_delta expected_balance[:balance], tsb.value, 0.0001, "Balance incorrect on date: #{tsb.date}"
- end
+ assert_equal Money.new(50000 - 1000, @family.currency), @family.net_worth
end
test "should exclude disabled accounts from calculations" do
- assets_before = @family.assets
- liabilities_before = @family.liabilities
- net_worth_before = @family.net_worth
+ cc = @family.accounts.create!(balance: 1000, accountable: CreditCard.new)
+ @family.accounts.create!(balance: 50000, accountable: Depository.new)
- disabled_checking = accounts(:checking)
- disabled_cc = accounts(:credit_card)
+ assert_equal Money.new(50000 - 1000, @family.currency), @family.net_worth
- disabled_checking.update!(is_active: false)
- disabled_cc.update!(is_active: false)
+ cc.update! is_active: false
- assert_equal assets_before - disabled_checking.balance, @family.assets
- assert_equal liabilities_before - disabled_cc.balance, @family.liabilities
- assert_equal net_worth_before - disabled_checking.balance + disabled_cc.balance, @family.net_worth
+ assert_equal Money.new(50000, @family.currency), @family.net_worth
end
- private
+ test "syncs active accounts" do
+ account = @family.accounts.create!(balance: 1000, accountable: CreditCard.new, is_active: false)
- def assert_time_series_balances(time_series_balances, expected_balances, ignore_count: false)
- assert_equal time_series_balances.values.count, expected_balances.count unless ignore_count
+ Account.any_instance.expects(:sync_later).never
- time_series_balances.values.each do |tsb|
- expected_balance = expected_balances.find { |eb| eb[:date] == tsb.date }
- assert_in_delta expected_balance[:balance], tsb.value.amount, 0.01, "Balance incorrect on date: #{tsb.date}"
- end
- end
+ @family.sync
+
+ account.update! is_active: true
+
+ Account.any_instance.expects(:sync_later).with(start_date: nil).once
+
+ @family.sync
+ end
+
+ test "calculates snapshot" do
+ asset = @family.accounts.create!(balance: 500, accountable: Depository.new)
+ liability = @family.accounts.create!(balance: 100, accountable: CreditCard.new)
+
+ asset.balances.create! date: 1.day.ago.to_date, currency: "USD", balance: 450
+ asset.balances.create! date: Date.current, currency: "USD", balance: 500
+
+ liability.balances.create! date: 1.day.ago.to_date, currency: "USD", balance: 50
+ liability.balances.create! date: Date.current, currency: "USD", balance: 100
+
+ expected_asset_series = [
+ { date: 1.day.ago.to_date, value: Money.new(450) },
+ { date: Date.current, value: Money.new(500) }
+ ]
+
+ expected_liability_series = [
+ { date: 1.day.ago.to_date, value: Money.new(50) },
+ { date: Date.current, value: Money.new(100) }
+ ]
+
+ expected_net_worth_series = [
+ { date: 1.day.ago.to_date, value: Money.new(450 - 50) },
+ { date: Date.current, value: Money.new(500 - 100) }
+ ]
+
+ assert_equal expected_asset_series, @family.snapshot[:asset_series].values.map { |v| { date: v.date, value: v.value } }
+ assert_equal expected_liability_series, @family.snapshot[:liability_series].values.map { |v| { date: v.date, value: v.value } }
+ assert_equal expected_net_worth_series, @family.snapshot[:net_worth_series].values.map { |v| { date: v.date, value: v.value } }
+ end
+
+ test "calculates top movers" do
+ checking_account = @family.accounts.create!(balance: 500, accountable: Depository.new)
+ savings_account = @family.accounts.create!(balance: 1000, accountable: Depository.new)
+
+ create_transaction(account: checking_account, date: 2.days.ago.to_date, amount: -1000)
+ create_transaction(account: checking_account, date: 1.day.ago.to_date, amount: 10)
+ create_transaction(account: savings_account, date: 2.days.ago.to_date, amount: -5000)
+
+ snapshot = @family.snapshot_account_transactions
+ top_spenders = snapshot[:top_spenders]
+ top_earners = snapshot[:top_earners]
+ top_savers = snapshot[:top_savers]
+
+ assert_equal 10, top_spenders.first.spending
+
+ assert_equal 5000, top_earners.first.income
+ assert_equal 1000, top_earners.second.income
+
+ assert_equal 1, top_savers.first.savings_rate
+ assert_equal ((1000 - 10).to_f / 1000), top_savers.second.savings_rate
+ end
+
+ test "calculates rolling transaction totals" do
+ account = @family.accounts.create!(balance: 1000, accountable: Depository.new)
+ create_transaction(account: account, date: 2.days.ago.to_date, amount: -500)
+ create_transaction(account: account, date: 1.day.ago.to_date, amount: 100)
+ create_transaction(account: account, date: Date.current, amount: 20)
+
+ snapshot = @family.snapshot_transactions
+
+ expected_income_series = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 500, 500, 500
+ ]
+
+ assert_equal expected_income_series, snapshot[:income_series].values.map(&:value).map(&:amount)
+
+ expected_spending_series = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 100, 120
+ ]
+
+ assert_equal expected_spending_series, snapshot[:spending_series].values.map(&:value).map(&:amount)
+
+ expected_savings_rate_series = [
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 1, 0.8, 0.76
+ ]
+
+ assert_equal expected_savings_rate_series, snapshot[:savings_rate_series].values.map(&:value).map { |v| v.round(2) }
+ end
end
diff --git a/test/models/tag_test.rb b/test/models/tag_test.rb
index 26582fc6..2d4cba2d 100644
--- a/test/models/tag_test.rb
+++ b/test/models/tag_test.rb
@@ -2,8 +2,8 @@ require "test_helper"
class TagTest < ActiveSupport::TestCase
test "replace and destroy" do
- old_tag = tags(:hawaii_trip)
- new_tag = tags(:trips)
+ old_tag = tags(:one)
+ new_tag = tags(:two)
assert_difference "Tag.count", -1 do
old_tag.replace_and_destroy!(new_tag)
diff --git a/test/models/value_group_test.rb b/test/models/value_group_test.rb
index 3b0c676d..e27010a1 100644
--- a/test/models/value_group_test.rb
+++ b/test/models/value_group_test.rb
@@ -2,10 +2,6 @@ require "test_helper"
require "ostruct"
class ValueGroupTest < ActiveSupport::TestCase
setup do
- checking = accounts(:checking)
- savings = accounts(:savings)
- collectable = accounts(:collectable)
-
# Level 1
@assets = ValueGroup.new("Assets", :usd)
diff --git a/test/support/account/entries_test_helper.rb b/test/support/account/entries_test_helper.rb
new file mode 100644
index 00000000..4a4dd339
--- /dev/null
+++ b/test/support/account/entries_test_helper.rb
@@ -0,0 +1,30 @@
+module Account::EntriesTestHelper
+ def create_transaction(attributes = {})
+ entry_attributes = attributes.except(:category, :tags, :merchant)
+ transaction_attributes = attributes.slice(:category, :tags, :merchant)
+
+ entry_defaults = {
+ account: accounts(:depository),
+ name: "Transaction",
+ date: Date.current,
+ currency: "USD",
+ amount: 100,
+ entryable: Account::Transaction.new(transaction_attributes)
+ }
+
+ Account::Entry.create! entry_defaults.merge(entry_attributes)
+ end
+
+ def create_valuation(attributes = {})
+ entry_defaults = {
+ account: accounts(:depository),
+ name: "Valuation",
+ date: 1.day.ago.to_date,
+ currency: "USD",
+ amount: 5000,
+ entryable: Account::Valuation.new
+ }
+
+ Account::Entry.create! entry_defaults.merge(attributes)
+ end
+end
diff --git a/test/support/family_snapshot_test_helper.rb b/test/support/family_snapshot_test_helper.rb
deleted file mode 100644
index f691f34f..00000000
--- a/test/support/family_snapshot_test_helper.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-module FamilySnapshotTestHelper
- # See: https://docs.google.com/spreadsheets/d/18LN5N-VLq4b49Mq1fNwF7_eBiHSQB46qQduRtdAEN98/edit?usp=sharing
- def get_expected_balances_for(key)
- expected_results_file.map do |row|
- {
- date: (Date.current - row["date_offset"].to_i.days).to_date,
- balance: row[key.to_s].to_d
- }
- end
- end
-
- def get_today_snapshot_value_for(metric)
- expected_results_file[-1][metric.to_s].to_d
- end
-
- private
-
- def expected_results_file
- CSV.read("test/fixtures/files/expected_family_snapshots.csv", headers: true)
- end
-end
diff --git a/test/system/transactions_test.rb b/test/system/transactions_test.rb
index 6516e3ed..25a75223 100644
--- a/test/system/transactions_test.rb
+++ b/test/system/transactions_test.rb
@@ -4,24 +4,28 @@ class TransactionsTest < ApplicationSystemTestCase
setup do
sign_in @user = users(:family_admin)
+ Account::Entry.delete_all # clean slate
+
+ create_transaction("one", 12.days.ago.to_date, 100)
+ create_transaction("two", 10.days.ago.to_date, 100)
+ create_transaction("three", 9.days.ago.to_date, 100)
+ create_transaction("four", 8.days.ago.to_date, 100)
+ create_transaction("five", 7.days.ago.to_date, 100)
+ create_transaction("six", 7.days.ago.to_date, 100)
+ create_transaction("seven", 4.days.ago.to_date, 100)
+ create_transaction("eight", 3.days.ago.to_date, 100)
+ create_transaction("nine", 1.days.ago.to_date, 100)
+ create_transaction("ten", 1.days.ago.to_date, 100)
+ create_transaction("eleven", Date.current, 100, category: categories(:food_and_drink), tags: [ tags(:one) ], merchant: merchants(:amazon))
+
+ @transactions = @user.family.entries
+ .account_transactions
+ .reverse_chronological
+
+ @transaction = @transactions.first
+
@page_size = 10
- @latest_transactions = @user.family.entries
- .account_transactions
- .without_transfers
- .reverse_chronological
- .limit(20).to_a
- @test_category = @user.family.categories.create! name: "System Test Category"
- @test_merchant = @user.family.merchants.create! name: "System Test Merchant"
-
- @target_txn = @user.family.accounts.first.entries.create! \
- name: "Oldest transaction",
- date: 10.years.ago.to_date,
- currency: @user.family.currency,
- amount: 100,
- entryable: Account::Transaction.new(category: @test_category,
- merchant: @test_merchant)
-
visit transactions_url(per_page: @page_size)
end
@@ -29,13 +33,13 @@ class TransactionsTest < ApplicationSystemTestCase
assert_selector "h1", text: "Transactions"
within "form#transactions-search" do
- fill_in "Search transactions by name", with: @target_txn.name
+ fill_in "Search transactions by name", with: @transaction.name
end
- assert_selector "#" + dom_id(@target_txn), count: 1
+ assert_selector "#" + dom_id(@transaction), count: 1
within "#transaction-search-filters" do
- assert_text @target_txn.name
+ assert_text @transaction.name
end
end
@@ -43,30 +47,34 @@ class TransactionsTest < ApplicationSystemTestCase
find("#transaction-filters-button").click
within "#transaction-filters-menu" do
- check(@target_txn.account.name)
+ check(@transaction.account.name)
click_button "Category"
- check(@test_category.name)
+ check(@transaction.account_transaction.category.name)
click_button "Apply"
end
- assert_selector "#" + dom_id(@target_txn), count: 1
+ assert_selector "#" + dom_id(@transaction), count: 1
within "#transaction-search-filters" do
- assert_text @target_txn.account.name
- assert_text @target_txn.account_transaction.category.name
+ assert_text @transaction.account.name
+ assert_text @transaction.account_transaction.category.name
end
end
test "all filters work and empty state shows if no match" do
find("#transaction-filters-button").click
+ account = @transaction.account
+ category = @transaction.account_transaction.category
+ merchant = @transaction.account_transaction.merchant
+
within "#transaction-filters-menu" do
click_button "Account"
- check(@target_txn.account.name)
+ check(account.name)
click_button "Date"
fill_in "q_start_date", with: 10.days.ago.to_date
- fill_in "q_end_date", with: Date.current
+ fill_in "q_end_date", with: 1.day.ago.to_date
click_button "Type"
assert_text "Filter by type coming soon..."
@@ -75,10 +83,10 @@ class TransactionsTest < ApplicationSystemTestCase
assert_text "Filter by amount coming soon..."
click_button "Category"
- check(@test_category.name)
+ check(category.name)
click_button "Merchant"
- check(@test_merchant.name)
+ check(merchant.name)
click_button "Apply"
end
@@ -91,14 +99,14 @@ class TransactionsTest < ApplicationSystemTestCase
assert_text "No entries found"
within "ul#transaction-search-filters" do
- find("li", text: @target_txn.account.name).first("a").click
+ find("li", text: account.name).first("a").click
find("li", text: "on or after #{10.days.ago.to_date}").first("a").click
- find("li", text: "on or before #{Date.current}").first("a").click
- find("li", text: @target_txn.account_transaction.category.name).first("a").click
- find("li", text: @target_txn.account_transaction.merchant.name).first("a").click
+ find("li", text: "on or before #{1.day.ago.to_date}").first("a").click
+ find("li", text: category.name).first("a").click
+ find("li", text: merchant.name).first("a").click
end
- assert_selector "#" + dom_id(@user.family.entries.reverse_chronological.first), count: 1
+ assert_selector "#" + dom_id(@transaction), count: 1
end
test "can select and deselect entire page of transactions" do
@@ -109,36 +117,52 @@ class TransactionsTest < ApplicationSystemTestCase
end
test "can select and deselect groups of transactions" do
- date_transactions_checkbox(12.days.ago.to_date).check
- assert_selection_count(3)
- date_transactions_checkbox(12.days.ago.to_date).uncheck
+ date_transactions_checkbox(1.day.ago.to_date).check
+ assert_selection_count(2)
+
+ date_transactions_checkbox(1.day.ago.to_date).uncheck
assert_selection_count(0)
end
test "can select and deselect individual transactions" do
- transaction_checkbox(@latest_transactions.first).check
+ transaction_checkbox(@transactions.first).check
assert_selection_count(1)
- transaction_checkbox(@latest_transactions.second).check
+ transaction_checkbox(@transactions.second).check
assert_selection_count(2)
- transaction_checkbox(@latest_transactions.second).uncheck
+ transaction_checkbox(@transactions.second).uncheck
assert_selection_count(1)
end
test "outermost group always overrides inner selections" do
- transaction_checkbox(@latest_transactions.first).check
+ transaction_checkbox(@transactions.first).check
assert_selection_count(1)
+
all_transactions_checkbox.check
assert_selection_count(number_of_transactions_on_page)
- transaction_checkbox(@latest_transactions.first).uncheck
+
+ transaction_checkbox(@transactions.first).uncheck
assert_selection_count(number_of_transactions_on_page - 1)
- date_transactions_checkbox(12.days.ago.to_date).uncheck
- assert_selection_count(number_of_transactions_on_page - 4)
+
+ date_transactions_checkbox(1.day.ago.to_date).uncheck
+ assert_selection_count(number_of_transactions_on_page - 3)
+
all_transactions_checkbox.uncheck
assert_selection_count(0)
end
private
+ def create_transaction(name, date, amount, category: nil, merchant: nil, tags: [])
+ account = accounts(:depository)
+
+ account.entries.create! \
+ name: name,
+ date: date,
+ amount: amount,
+ currency: "USD",
+ entryable: Account::Transaction.new(category: category, merchant: merchant, tags: tags)
+ end
+
def number_of_transactions_on_page
[ @user.family.entries.without_transfers.count, @page_size ].min
end
diff --git a/test/system/transfers_test.rb b/test/system/transfers_test.rb
index 48d51b5c..702ca81f 100644
--- a/test/system/transfers_test.rb
+++ b/test/system/transfers_test.rb
@@ -7,8 +7,8 @@ class TransfersTest < ApplicationSystemTestCase
end
test "can create a transfer" do
- checking_name = accounts(:checking).name
- savings_name = accounts(:savings).name
+ checking_name = accounts(:depository).name
+ savings_name = accounts(:credit_card).name
transfer_date = Date.current
click_on "New transaction"
@@ -32,15 +32,15 @@ class TransfersTest < ApplicationSystemTestCase
test "can match 2 transactions and create a transfer" do
transfer_date = Date.current
- outflow = accounts(:savings).entries.create! \
- name: "Outflow from savings account",
+ outflow = accounts(:depository).entries.create! \
+ name: "Outflow from checking account",
date: transfer_date,
amount: 100,
currency: "USD",
entryable: Account::Transaction.new
- inflow = accounts(:checking).entries.create! \
- name: "Inflow to checking account",
+ inflow = accounts(:credit_card).entries.create! \
+ name: "Inflow to cc account",
date: transfer_date,
amount: -100,
currency: "USD",
@@ -64,7 +64,7 @@ class TransfersTest < ApplicationSystemTestCase
txn = @user.family.entries.reverse_chronological.first
within "#" + dom_id(txn) do
- assert_text "Uncategorized"
+ assert_text txn.account_transaction.category.name || "Uncategorized"
end
transaction_entry_checkbox(txn).check