diff --git a/app/components/UI/account/activity_feed.html.erb b/app/components/UI/account/activity_feed.html.erb index 38c179552..fe5041f13 100644 --- a/app/components/UI/account/activity_feed.html.erb +++ b/app/components/UI/account/activity_feed.html.erb @@ -37,7 +37,7 @@ variant: "link", text: t("accounts.show.activity.new_transfer"), icon: "arrow-right-left", - href: new_transfer_path, + href: new_transfer_path(from_account_id: account.id), data: { turbo_frame: :modal }) %> <% end %> diff --git a/app/controllers/transfers_controller.rb b/app/controllers/transfers_controller.rb index 7342414bb..db4343584 100644 --- a/app/controllers/transfers_controller.rb +++ b/app/controllers/transfers_controller.rb @@ -5,6 +5,7 @@ class TransfersController < ApplicationController def new @transfer = Transfer.new + @from_account_id = params[:from_account_id] end def show diff --git a/app/models/account/provider_import_adapter.rb b/app/models/account/provider_import_adapter.rb index 3c28db52a..28bf61cf9 100644 --- a/app/models/account/provider_import_adapter.rb +++ b/app/models/account/provider_import_adapter.rb @@ -155,7 +155,7 @@ class Account::ProviderImportAdapter auto_kind = "funds_movement" elsif detected_label == "Contribution" auto_kind = "investment_contribution" - auto_category = account.family.categories.find_by(name: "Investment Contributions") + auto_category = account.family.categories.find_by(name: Category::DEFAULT_INVESTMENT_CONTRIBUTIONS_NAME) end # Set investment activity label, kind, and category if detected diff --git a/app/models/category.rb b/app/models/category.rb index b6586492e..3dfb8a809 100644 --- a/app/models/category.rb +++ b/app/models/category.rb @@ -39,6 +39,10 @@ class Category < ApplicationRecord UNCATEGORIZED_NAME_KEY = "models.category.uncategorized" OTHER_INVESTMENTS_NAME_KEY = "models.category.other_investments" + # Default category name for investment contributions (bootstrapped category) + # This is the canonical English name used when seeding categories via bootstrap! + DEFAULT_INVESTMENT_CONTRIBUTIONS_NAME = "Investment Contributions" + class Group attr_reader :category, :subcategories diff --git a/app/models/income_statement/totals.rb b/app/models/income_statement/totals.rb index 1de3e081c..7bb9f67dc 100644 --- a/app/models/income_statement/totals.rb +++ b/app/models/income_statement/totals.rb @@ -57,7 +57,7 @@ class IncomeStatement::Totals c.id as category_id, c.parent_id as parent_category_id, CASE WHEN at.kind = 'investment_contribution' THEN 'expense' WHEN ae.amount < 0 THEN 'income' ELSE 'expense' END as classification, - ABS(SUM(ae.amount * COALESCE(er.rate, 1))) as total, + ABS(SUM(CASE WHEN at.kind = 'investment_contribution' THEN ABS(ae.amount * COALESCE(er.rate, 1)) ELSE ae.amount * COALESCE(er.rate, 1) END)) as total, COUNT(ae.id) as transactions_count, false as is_uncategorized_investment FROM (#{@transactions_scope.to_sql}) at @@ -83,7 +83,7 @@ class IncomeStatement::Totals c.id as category_id, c.parent_id as parent_category_id, CASE WHEN at.kind = 'investment_contribution' THEN 'expense' WHEN ae.amount < 0 THEN 'income' ELSE 'expense' END as classification, - ABS(SUM(ae.amount * COALESCE(er.rate, 1))) as total, + ABS(SUM(CASE WHEN at.kind = 'investment_contribution' THEN ABS(ae.amount * COALESCE(er.rate, 1)) ELSE ae.amount * COALESCE(er.rate, 1) END)) as total, COUNT(ae.id) as entry_count, false as is_uncategorized_investment FROM (#{@transactions_scope.to_sql}) at diff --git a/app/models/transfer/creator.rb b/app/models/transfer/creator.rb index 61bbadeeb..70b143b24 100644 --- a/app/models/transfer/creator.rb +++ b/app/models/transfer/creator.rb @@ -43,7 +43,7 @@ class Transfer::Creator end def investment_contributions_category - source_account.family.categories.find_by(name: "Investment Contributions") + source_account.family.categories.find_by(name: Category::DEFAULT_INVESTMENT_CONTRIBUTIONS_NAME) end def inflow_transaction diff --git a/app/views/transfers/_form.html.erb b/app/views/transfers/_form.html.erb index b32e59707..4158303e4 100644 --- a/app/views/transfers/_form.html.erb +++ b/app/views/transfers/_form.html.erb @@ -11,7 +11,7 @@
- <%= f.collection_select :from_account_id, Current.family.accounts.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".from") }, required: true %> + <%= f.collection_select :from_account_id, Current.family.accounts.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".from"), selected: @from_account_id }, required: true %> <%= f.collection_select :to_account_id, Current.family.accounts.alphabetically, :id, :name, { prompt: t(".select_account"), label: t(".to") }, required: true %> <%= f.number_field :amount, label: t(".amount"), required: true, min: 0, placeholder: "100", step: 0.00000001 %> <%= f.date_field :date, value: transfer.inflow_transaction&.entry&.date || Date.current, label: t(".date"), required: true, max: Date.current %> diff --git a/test/models/transfer/creator_test.rb b/test/models/transfer/creator_test.rb index ff168509f..4f1a2a163 100644 --- a/test/models/transfer/creator_test.rb +++ b/test/models/transfer/creator_test.rb @@ -7,16 +7,11 @@ class Transfer::CreatorTest < ActiveSupport::TestCase @destination_account = accounts(:investment) @date = Date.current @amount = 100 + # Ensure the Investment Contributions category exists for transfer tests + @investment_category = ensure_investment_contributions_category(@family) end test "creates investment contribution when transferring from depository to investment" do - # Ensure the Investment Contributions category exists with all required attributes - investment_category = @family.categories.find_or_create_by!(name: "Investment Contributions") do |c| - c.color = "#0d9488" - c.lucide_icon = "trending-up" - c.classification = "expense" - end - creator = Transfer::Creator.new( family: @family, source_account_id: @source_account.id, @@ -36,7 +31,7 @@ class Transfer::CreatorTest < ActiveSupport::TestCase assert_equal @amount, outflow.entry.amount assert_equal @source_account.currency, outflow.entry.currency assert_equal "Transfer to #{@destination_account.name}", outflow.entry.name - assert_equal investment_category, outflow.category, "Should auto-assign Investment Contributions category" + assert_equal @investment_category, outflow.category, "Should auto-assign Investment Contributions category" # Verify inflow transaction (always funds_movement) inflow = transfer.inflow_transaction @@ -75,13 +70,7 @@ class Transfer::CreatorTest < ActiveSupport::TestCase end test "creates investment contribution when transferring from depository to crypto" do - # Use crypto account - transfer from depository should be investment_contribution crypto_account = accounts(:crypto) - investment_category = @family.categories.find_or_create_by!(name: "Investment Contributions") do |c| - c.color = "#0d9488" - c.lucide_icon = "trending-up" - c.classification = "expense" - end creator = Transfer::Creator.new( family: @family, @@ -99,7 +88,7 @@ class Transfer::CreatorTest < ActiveSupport::TestCase outflow = transfer.outflow_transaction assert_equal "investment_contribution", outflow.kind assert_equal "Transfer to #{crypto_account.name}", outflow.entry.name - assert_equal investment_category, outflow.category + assert_equal @investment_category, outflow.category # Verify inflow transaction with currency handling inflow = transfer.inflow_transaction diff --git a/test/test_helper.rb b/test/test_helper.rb index 16bab4495..b44fcdeb3 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -78,6 +78,16 @@ module ActiveSupport def user_password_test "maybetestpassword817983172" end + + # Ensures the Investment Contributions category exists for a family + # Used in transfer tests where this bootstrapped category is required + def ensure_investment_contributions_category(family) + family.categories.find_or_create_by!(name: Category::DEFAULT_INVESTMENT_CONTRIBUTIONS_NAME) do |c| + c.color = "#0d9488" + c.lucide_icon = "trending-up" + c.classification = "expense" + end + end end end