diff --git a/app/models/account/provider_import_adapter.rb b/app/models/account/provider_import_adapter.rb index 31d65a6ae..dac0da8d4 100644 --- a/app/models/account/provider_import_adapter.rb +++ b/app/models/account/provider_import_adapter.rb @@ -119,11 +119,12 @@ class Account::ProviderImportAdapter # Set investment activity label if provided and not already set if investment_activity_label.present? && entry.entryable.is_a?(Transaction) if entry.transaction.investment_activity_label.blank? - entry.transaction.update!(investment_activity_label: investment_activity_label) + entry.transaction.assign_attributes(investment_activity_label: investment_activity_label) end end entry.save! + entry.transaction.save! if entry.transaction.changed? # AFTER save: For NEW posted transactions, check for fuzzy matches to SUGGEST (not auto-claim) # This handles tip adjustments where auto-matching is too risky diff --git a/app/models/investment_activity_detector.rb b/app/models/investment_activity_detector.rb index c030d9cdf..2ef6c2f71 100644 --- a/app/models/investment_activity_detector.rb +++ b/app/models/investment_activity_detector.rb @@ -119,8 +119,9 @@ class InvestmentActivityDetector end # Check for dividend patterns - if description == "CASH" || description.include?("DIVIDEND") || - description.include?("DISTRIBUTION") + # "CASH" alone typically indicates dividend payout in brokerage feeds (only for inflows) + if description.include?("DIVIDEND") || description.include?("DISTRIBUTION") || + (description == "CASH" && amount < 0) return "Dividend" end diff --git a/app/views/transactions/_transaction.html.erb b/app/views/transactions/_transaction.html.erb index a4593a56d..c645d515d 100644 --- a/app/views/transactions/_transaction.html.erb +++ b/app/views/transactions/_transaction.html.erb @@ -87,7 +87,7 @@ <%# Investment activity label badge %> <% if transaction.investment_activity_label.present? %> "> - <%= transaction.investment_activity_label %> + <%= t("transactions.activity_labels.#{transaction.investment_activity_label.parameterize(separator: '_')}") %> <% end %> diff --git a/app/views/transactions/show.html.erb b/app/views/transactions/show.html.erb index 85e770509..4af991f1a 100644 --- a/app/views/transactions/show.html.erb +++ b/app/views/transactions/show.html.erb @@ -240,7 +240,7 @@ <%= ef.select :investment_activity_label, options_for_select( - [["—", nil]] + Transaction::ACTIVITY_LABELS.map { |l| [l, l] }, + [["—", nil]] + Transaction::ACTIVITY_LABELS.map { |l| [t("transactions.activity_labels.#{l.parameterize(separator: '_')}"), l] }, @entry.entryable.investment_activity_label ), { label: false }, @@ -260,8 +260,8 @@ <%= f.fields_for :entryable do |ef| %>
-

One-time <%= @entry.amount.negative? ? "Income" : "Expense" %>

-

One-time transactions will be excluded from certain budgeting calculations and reports to help you see what's really important.

+

<%= t(".one_time_title", type: @entry.amount.negative? ? t("transactions.form.income") : t("transactions.form.expense")) %>

+

<%= t(".one_time_description") %>

<%= ef.toggle :kind, { diff --git a/config/locales/views/transactions/en.yml b/config/locales/views/transactions/en.yml index 0a393d835..267adce43 100644 --- a/config/locales/views/transactions/en.yml +++ b/config/locales/views/transactions/en.yml @@ -38,6 +38,22 @@ en: exclude_from_cashflow_description_investment: Hide from income/expense reports and Sankey chart. Use for internal investment activity like fund swaps, reinvestments, or money market sweeps. activity_type: Activity Type activity_type_description: Type of investment activity (Buy, Sell, Dividend, etc.). Auto-detected or set manually. + one_time_title: One-time %{type} + one_time_description: One-time transactions will be excluded from certain budgeting calculations and reports to help you see what's really important. + activity_labels: + buy: Buy + sell: Sell + sweep_in: Sweep In + sweep_out: Sweep Out + dividend: Dividend + reinvestment: Reinvestment + interest: Interest + fee: Fee + transfer: Transfer + contribution: Contribution + withdrawal: Withdrawal + exchange: Exchange + other: Other mark_recurring: Mark as Recurring mark_recurring_subtitle: Track this as a recurring transaction. Amount variance is automatically calculated from past 6 months of similar transactions. mark_recurring_title: Recurring Transaction diff --git a/lib/tasks/investment_labels.rake b/lib/tasks/investment_labels.rake index 31741574a..9cefae7c9 100644 --- a/lib/tasks/investment_labels.rake +++ b/lib/tasks/investment_labels.rake @@ -78,6 +78,7 @@ namespace :sure do # Find transactions (optionally include already-labeled if force=true) entries = account.entries .joins("INNER JOIN transactions ON transactions.id = entries.entryable_id AND entries.entryable_type = 'Transaction'") + .includes(:entryable) unless force entries = entries.where("transactions.investment_activity_label IS NULL OR transactions.investment_activity_label = ''") @@ -160,8 +161,11 @@ namespace :sure do true elsif %w[1 true yes y].include?(dry_raw) true - else + elsif %w[0 false no n].include?(dry_raw) false + else + puts({ ok: false, error: "invalid_argument", message: "dry_run must be one of: true/yes/1 or false/no/0" }.to_json) + exit 1 end account = Account.find(account_id)