1
0
Fork 0
mirror of https://github.com/maybe-finance/maybe.git synced 2025-07-19 13:19:39 +02:00

Account:: namespace simplifications and cleanup (#2110)

* Flatten Holding model

* Flatten balance model

* Entries domain renames

* Fix valuations reference

* Fix trades stream

* Fix brakeman warnings

* Fix tests

* Replace existing entryable type references in DB
This commit is contained in:
Zach Gollwitzer 2025-04-14 11:40:34 -04:00 committed by GitHub
parent f181ba941f
commit e657c40d19
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
172 changed files with 1297 additions and 1258 deletions

View file

@ -1,119 +0,0 @@
require "test_helper"
class Account::TransactionsControllerTest < ActionDispatch::IntegrationTest
include EntryableResourceInterfaceTest
setup do
sign_in @user = users(:family_admin)
@entry = account_entries(:transaction)
end
test "creates with transaction details" do
assert_difference [ "Account::Entry.count", "Account::Transaction.count" ], 1 do
post account_transactions_url, params: {
account_entry: {
account_id: @entry.account_id,
name: "New transaction",
date: Date.current,
currency: "USD",
amount: 100,
nature: "inflow",
entryable_attributes: {
tag_ids: [ Tag.first.id, Tag.second.id ],
category_id: Category.first.id,
merchant_id: Merchant.first.id
}
}
}
end
created_entry = Account::Entry.order(:created_at).last
assert_redirected_to account_url(created_entry.account)
assert_equal "Entry created", flash[:notice]
assert_enqueued_with(job: SyncJob)
end
test "updates with transaction details" do
assert_no_difference [ "Account::Entry.count", "Account::Transaction.count" ] do
patch account_transaction_url(@entry), params: {
account_entry: {
name: "Updated name",
date: Date.current,
currency: "USD",
amount: 100,
nature: "inflow",
entryable_type: @entry.entryable_type,
notes: "test notes",
excluded: false,
entryable_attributes: {
id: @entry.entryable_id,
tag_ids: [ Tag.first.id, Tag.second.id ],
category_id: Category.first.id,
merchant_id: Merchant.first.id
}
}
}
end
@entry.reload
assert_equal "Updated name", @entry.name
assert_equal Date.current, @entry.date
assert_equal "USD", @entry.currency
assert_equal -100, @entry.amount
assert_equal [ Tag.first.id, Tag.second.id ], @entry.entryable.tag_ids.sort
assert_equal Category.first.id, @entry.entryable.category_id
assert_equal Merchant.first.id, @entry.entryable.merchant_id
assert_equal "test notes", @entry.notes
assert_equal false, @entry.excluded
assert_equal "Entry updated", flash[:notice]
assert_redirected_to account_url(@entry.account)
assert_enqueued_with(job: SyncJob)
end
test "can destroy many transactions at once" do
transactions = @user.family.entries.account_transactions
delete_count = transactions.size
assert_difference([ "Account::Transaction.count", "Account::Entry.count" ], -delete_count) do
post bulk_delete_account_transactions_url, params: {
bulk_delete: {
entry_ids: transactions.pluck(:id)
}
}
end
assert_redirected_to transactions_url
assert_equal "#{delete_count} transactions deleted", flash[:notice]
end
test "can update many transactions at once" do
transactions = @user.family.entries.account_transactions
assert_difference [ "Account::Entry.count", "Account::Transaction.count" ], 0 do
post bulk_update_account_transactions_url, params: {
bulk_update: {
entry_ids: transactions.map(&:id),
date: 1.day.ago.to_date,
category_id: Category.second.id,
merchant_id: Merchant.second.id,
tag_ids: [ Tag.first.id, Tag.second.id ],
notes: "Updated note"
}
}
end
assert_redirected_to transactions_url
assert_equal "#{transactions.count} transactions updated", flash[:notice]
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
assert_equal "Updated note", transaction.notes
assert_equal [ Tag.first.id, Tag.second.id ], transaction.entryable.tag_ids.sort
end
end
end

View file

@ -3,7 +3,7 @@ require "test_helper"
class CategoriesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:family_admin)
@transaction = account_transactions :one
@transaction = transactions :one
end
test "index" do

View file

@ -30,7 +30,7 @@ class Category::DeletionsControllerTest < ActionDispatch::IntegrationTest
assert_not_empty @category.transactions
assert_difference "Category.count", -1 do
assert_difference "Account::Transaction.where(category: nil).count", @category.transactions.count do
assert_difference "Transaction.where(category: nil).count", @category.transactions.count do
post category_deletions_url(@category)
end
end

View file

@ -11,8 +11,8 @@ class CreditCardsControllerTest < ActionDispatch::IntegrationTest
test "creates with credit card details" do
assert_difference -> { Account.count } => 1,
-> { CreditCard.count } => 1,
-> { Account::Valuation.count } => 2,
-> { Account::Entry.count } => 2 do
-> { Valuation.count } => 2,
-> { Entry.count } => 2 do
post credit_cards_path, params: {
account: {
name: "New Credit Card",

View file

@ -1,6 +1,6 @@
require "test_helper"
class Account::HoldingsControllerTest < ActionDispatch::IntegrationTest
class HoldingsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in users(:family_admin)
@account = accounts(:investment)
@ -8,20 +8,20 @@ class Account::HoldingsControllerTest < ActionDispatch::IntegrationTest
end
test "gets holdings" do
get account_holdings_url(account_id: @account.id)
get holdings_url(account_id: @account.id)
assert_response :success
end
test "gets holding" do
get account_holding_path(@holding)
get holding_path(@holding)
assert_response :success
end
test "destroys holding and associated entries" do
assert_difference -> { Account::Holding.count } => -1,
-> { Account::Entry.count } => -1 do
delete account_holding_path(@holding)
assert_difference -> { Holding.count } => -1,
-> { Entry.count } => -1 do
delete holding_path(@holding)
end
assert_redirected_to account_path(@holding.account)

View file

@ -11,8 +11,8 @@ class LoansControllerTest < ActionDispatch::IntegrationTest
test "creates with loan details" do
assert_difference -> { Account.count } => 1,
-> { Loan.count } => 1,
-> { Account::Valuation.count } => 2,
-> { Account::Entry.count } => 2 do
-> { Valuation.count } => 2,
-> { Entry.count } => 2 do
post loans_path, params: {
account: {
name: "New Loan",

View file

@ -11,8 +11,8 @@ class PropertiesControllerTest < ActionDispatch::IntegrationTest
test "creates with property details" do
assert_difference -> { Account.count } => 1,
-> { Property.count } => 1,
-> { Account::Valuation.count } => 2,
-> { Account::Entry.count } => 2 do
-> { Valuation.count } => 2,
-> { Entry.count } => 2 do
post properties_path, params: {
account: {
name: "Property",

View file

@ -64,8 +64,8 @@ class Settings::HostingsControllerTest < ActionDispatch::IntegrationTest
assert_not ExchangeRate.exists?(exchange_rate.id)
assert_not Security::Price.exists?(security_price.id)
assert_not Account::Holding.exists?(holding.id)
assert_not Account::Balance.exists?(account_balance.id)
assert_not Holding.exists?(holding.id)
assert_not Balance.exists?(account_balance.id)
end
test "can clear data only when admin" do

View file

@ -1,17 +1,17 @@
require "test_helper"
class Account::TradesControllerTest < ActionDispatch::IntegrationTest
class TradesControllerTest < ActionDispatch::IntegrationTest
include EntryableResourceInterfaceTest
setup do
sign_in @user = users(:family_admin)
@entry = account_entries(:trade)
@entry = entries(:trade)
end
test "updates trade entry" do
assert_no_difference [ "Account::Entry.count", "Account::Trade.count" ] do
patch account_trade_url(@entry), params: {
account_entry: {
assert_no_difference [ "Entry.count", "Trade.count" ] do
patch trade_url(@entry), params: {
entry: {
currency: "USD",
entryable_attributes: {
id: @entry.entryable_id,
@ -26,8 +26,8 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
assert_enqueued_with job: SyncJob
assert_equal 20, @entry.account_trade.qty
assert_equal 20, @entry.account_trade.price
assert_equal 20, @entry.trade.qty
assert_equal 20, @entry.trade.price
assert_equal "USD", @entry.currency
assert_redirected_to account_url(@entry.account)
@ -36,11 +36,11 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
test "creates deposit entry" do
from_account = accounts(:depository) # Account the deposit is coming from
assert_difference -> { Account::Entry.count } => 2,
-> { Account::Transaction.count } => 2,
assert_difference -> { Entry.count } => 2,
-> { Transaction.count } => 2,
-> { Transfer.count } => 1 do
post account_trades_url, params: {
account_entry: {
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "deposit",
date: Date.current,
@ -57,11 +57,11 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
test "creates withdrawal entry" do
to_account = accounts(:depository) # Account the withdrawal is going to
assert_difference -> { Account::Entry.count } => 2,
-> { Account::Transaction.count } => 2,
assert_difference -> { Entry.count } => 2,
-> { Transaction.count } => 2,
-> { Transfer.count } => 1 do
post account_trades_url, params: {
account_entry: {
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "withdrawal",
date: Date.current,
@ -76,11 +76,11 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
end
test "deposit and withdrawal has optional transfer account" do
assert_difference -> { Account::Entry.count } => 1,
-> { Account::Transaction.count } => 1,
assert_difference -> { Entry.count } => 1,
-> { Transaction.count } => 1,
-> { Transfer.count } => 0 do
post account_trades_url, params: {
account_entry: {
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "withdrawal",
date: Date.current,
@ -90,16 +90,16 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
}
end
created_entry = Account::Entry.order(created_at: :desc).first
created_entry = Entry.order(created_at: :desc).first
assert created_entry.amount.positive?
assert_redirected_to @entry.account
end
test "creates interest entry" do
assert_difference [ "Account::Entry.count", "Account::Transaction.count" ], 1 do
post account_trades_url, params: {
account_entry: {
assert_difference [ "Entry.count", "Transaction.count" ], 1 do
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "interest",
date: Date.current,
@ -109,16 +109,16 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
}
end
created_entry = Account::Entry.order(created_at: :desc).first
created_entry = Entry.order(created_at: :desc).first
assert created_entry.amount.negative?
assert_redirected_to @entry.account
end
test "creates trade buy entry" do
assert_difference [ "Account::Entry.count", "Account::Trade.count", "Security.count" ], 1 do
post account_trades_url, params: {
account_entry: {
assert_difference [ "Entry.count", "Trade.count", "Security.count" ], 1 do
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "buy",
date: Date.current,
@ -130,19 +130,19 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
}
end
created_entry = Account::Entry.order(created_at: :desc).first
created_entry = Entry.order(created_at: :desc).first
assert created_entry.amount.positive?
assert created_entry.account_trade.qty.positive?
assert created_entry.trade.qty.positive?
assert_equal "Entry created", flash[:notice]
assert_enqueued_with job: SyncJob
assert_redirected_to account_url(created_entry.account)
end
test "creates trade sell entry" do
assert_difference [ "Account::Entry.count", "Account::Trade.count" ], 1 do
post account_trades_url, params: {
account_entry: {
assert_difference [ "Entry.count", "Trade.count" ], 1 do
post trades_url, params: {
entry: {
account_id: @entry.account_id,
type: "sell",
ticker: "AAPL (NYSE)",
@ -154,10 +154,10 @@ class Account::TradesControllerTest < ActionDispatch::IntegrationTest
}
end
created_entry = Account::Entry.order(created_at: :desc).first
created_entry = Entry.order(created_at: :desc).first
assert created_entry.amount.negative?
assert created_entry.account_trade.qty.negative?
assert created_entry.trade.qty.negative?
assert_equal "Entry created", flash[:notice]
assert_enqueued_with job: SyncJob
assert_redirected_to account_url(created_entry.account)

View file

@ -0,0 +1,24 @@
require "test_helper"
class Transactions::BulkDeletionsControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in @user = users(:family_admin)
@entry = entries(:transaction)
end
test "bulk delete" do
transactions = @user.family.entries.transactions
delete_count = transactions.size
assert_difference([ "Transaction.count", "Entry.count" ], -delete_count) do
post transactions_bulk_deletion_url, params: {
bulk_delete: {
entry_ids: transactions.pluck(:id)
}
}
end
assert_redirected_to transactions_url
assert_equal "#{delete_count} transactions deleted", flash[:notice]
end
end

View file

@ -0,0 +1,35 @@
require "test_helper"
class Transactions::BulkUpdatesControllerTest < ActionDispatch::IntegrationTest
setup do
sign_in @user = users(:family_admin)
end
test "bulk update" do
transactions = @user.family.entries.transactions
assert_difference [ "Entry.count", "Transaction.count" ], 0 do
post transactions_bulk_update_url, params: {
bulk_update: {
entry_ids: transactions.map(&:id),
date: 1.day.ago.to_date,
category_id: Category.second.id,
merchant_id: Merchant.second.id,
tag_ids: [ Tag.first.id, Tag.second.id ],
notes: "Updated note"
}
}
end
assert_redirected_to transactions_url
assert_equal "#{transactions.count} transactions updated", flash[:notice]
transactions.reload.each do |transaction|
assert_equal 1.day.ago.to_date, transaction.date
assert_equal Category.second, transaction.transaction.category
assert_equal Merchant.second, transaction.transaction.merchant
assert_equal "Updated note", transaction.notes
assert_equal [ Tag.first.id, Tag.second.id ], transaction.entryable.tag_ids.sort
end
end
end

View file

@ -1,11 +1,77 @@
require "test_helper"
class TransactionsControllerTest < ActionDispatch::IntegrationTest
include Account::EntriesTestHelper
include EntryableResourceInterfaceTest, EntriesTestHelper
setup do
sign_in @user = users(:family_admin)
@transaction = account_entries(:transaction)
@entry = entries(:transaction)
end
test "creates with transaction details" do
assert_difference [ "Entry.count", "Transaction.count" ], 1 do
post transactions_url, params: {
entry: {
account_id: @entry.account_id,
name: "New transaction",
date: Date.current,
currency: "USD",
amount: 100,
nature: "inflow",
entryable_type: @entry.entryable_type,
entryable_attributes: {
tag_ids: [ Tag.first.id, Tag.second.id ],
category_id: Category.first.id,
merchant_id: Merchant.first.id
}
}
}
end
created_entry = Entry.order(:created_at).last
assert_redirected_to account_url(created_entry.account)
assert_equal "Transaction created", flash[:notice]
assert_enqueued_with(job: SyncJob)
end
test "updates with transaction details" do
assert_no_difference [ "Entry.count", "Transaction.count" ] do
patch transaction_url(@entry), params: {
entry: {
name: "Updated name",
date: Date.current,
currency: "USD",
amount: 100,
nature: "inflow",
entryable_type: @entry.entryable_type,
notes: "test notes",
excluded: false,
entryable_attributes: {
id: @entry.entryable_id,
tag_ids: [ Tag.first.id, Tag.second.id ],
category_id: Category.first.id,
merchant_id: Merchant.first.id
}
}
}
end
@entry.reload
assert_equal "Updated name", @entry.name
assert_equal Date.current, @entry.date
assert_equal "USD", @entry.currency
assert_equal -100, @entry.amount
assert_equal [ Tag.first.id, Tag.second.id ], @entry.entryable.tag_ids.sort
assert_equal Category.first.id, @entry.entryable.category_id
assert_equal Merchant.first.id, @entry.entryable.merchant_id
assert_equal "test notes", @entry.notes
assert_equal false, @entry.excluded
assert_equal "Transaction updated", flash[:notice]
assert_redirected_to account_url(@entry.account)
assert_enqueued_with(job: SyncJob)
end
test "transaction count represents filtered total" do
@ -19,7 +85,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
get transactions_url(per_page: 10)
assert_dom "#total-transactions", count: 1, text: family.entries.account_transactions.size.to_s
assert_dom "#total-transactions", count: 1, text: family.entries.transactions.size.to_s
searchable_transaction = create_transaction(account: account, name: "Unique test name")
@ -39,7 +105,7 @@ class TransactionsControllerTest < ActionDispatch::IntegrationTest
create_transaction(account: account)
end
sorted_transactions = family.entries.account_transactions.reverse_chronological.to_a
sorted_transactions = family.entries.transactions.reverse_chronological.to_a
assert_equal 11, sorted_transactions.count

View file

@ -1,7 +1,7 @@
require "test_helper"
class Account::TransferMatchesControllerTest < ActionDispatch::IntegrationTest
include Account::EntriesTestHelper
class TransferMatchesControllerTest < ActionDispatch::IntegrationTest
include EntriesTestHelper
setup do
sign_in @user = users(:family_admin)
@ -12,7 +12,7 @@ class Account::TransferMatchesControllerTest < ActionDispatch::IntegrationTest
outflow_transaction = create_transaction(amount: -100, account: accounts(:investment))
assert_difference "Transfer.count", 1 do
post account_transaction_transfer_match_path(inflow_transaction), params: {
post transaction_transfer_match_path(inflow_transaction), params: {
transfer_match: {
method: "existing",
matched_entry_id: outflow_transaction.id
@ -27,8 +27,8 @@ class Account::TransferMatchesControllerTest < ActionDispatch::IntegrationTest
test "creates transfer for target account" do
inflow_transaction = create_transaction(amount: 100, account: accounts(:depository))
assert_difference [ "Transfer.count", "Account::Entry.count", "Account::Transaction.count" ], 1 do
post account_transaction_transfer_match_path(inflow_transaction), params: {
assert_difference [ "Transfer.count", "Entry.count", "Transaction.count" ], 1 do
post transaction_transfer_match_path(inflow_transaction), params: {
transfer_match: {
method: "new",
target_account_id: accounts(:investment).id

View file

@ -1,17 +1,18 @@
require "test_helper"
class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest
class ValuationsControllerTest < ActionDispatch::IntegrationTest
include EntryableResourceInterfaceTest
setup do
sign_in @user = users(:family_admin)
@entry = account_entries(:valuation)
@entry = entries(:valuation)
end
test "error when valuation already exists for date" do
assert_no_difference [ "Account::Entry.count", "Account::Valuation.count" ] do
post account_valuations_url(@entry.account), params: {
account_entry: {
assert_no_difference [ "Entry.count", "Valuation.count" ] do
post valuations_url(@entry.account), params: {
entry: {
account_id: @entry.account_id,
amount: 19800,
date: @entry.date,
currency: "USD"
@ -23,9 +24,9 @@ class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest
end
test "creates entry with basic attributes" do
assert_difference [ "Account::Entry.count", "Account::Valuation.count" ], 1 do
post account_valuations_url, params: {
account_entry: {
assert_difference [ "Entry.count", "Valuation.count" ], 1 do
post valuations_url, params: {
entry: {
name: "New entry",
amount: 10000,
currency: "USD",
@ -35,7 +36,7 @@ class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest
}
end
created_entry = Account::Entry.order(created_at: :desc).first
created_entry = Entry.order(created_at: :desc).first
assert_enqueued_with job: SyncJob
@ -43,9 +44,9 @@ class Account::ValuationsControllerTest < ActionDispatch::IntegrationTest
end
test "updates entry with basic attributes" do
assert_no_difference [ "Account::Entry.count", "Account::Valuation.count" ] do
patch account_valuation_url(@entry), params: {
account_entry: {
assert_no_difference [ "Entry.count", "Valuation.count" ] do
patch valuation_url(@entry), params: {
entry: {
name: "Updated entry",
amount: 20000,
currency: "USD",

View file

@ -11,8 +11,8 @@ class VehiclesControllerTest < ActionDispatch::IntegrationTest
test "creates with vehicle details" do
assert_difference -> { Account.count } => 1,
-> { Vehicle.count } => 1,
-> { Account::Valuation.count } => 2,
-> { Account::Entry.count } => 2 do
-> { Valuation.count } => 2,
-> { Entry.count } => 2 do
post vehicles_path, params: {
account: {
name: "Vehicle",