diff --git a/app/controllers/transactions/categorizes_controller.rb b/app/controllers/transactions/categorizes_controller.rb index 38a505029..b65ebea64 100644 --- a/app/controllers/transactions/categorizes_controller.rb +++ b/app/controllers/transactions/categorizes_controller.rb @@ -18,7 +18,7 @@ class Transactions::CategorizesController < ApplicationController @group = groups.first @categories = Current.family.categories.alphabetically - @total_uncategorized = Entry.uncategorized_count(Current.accessible_entries) + @total_uncategorized = uncategorized_count end def create @@ -60,7 +60,7 @@ class Transactions::CategorizesController < ApplicationController end streams << turbo_stream.replace("categorize_remaining", partial: "transactions/categorizes/remaining_count", - locals: { total_uncategorized: Entry.uncategorized_count(Current.accessible_entries) }) + locals: { total_uncategorized: uncategorized_count }) streams << turbo_stream.replace("categorize_group_summary", partial: "transactions/categorizes/group_summary", locals: { entries: remaining_entries }) @@ -98,7 +98,7 @@ class Transactions::CategorizesController < ApplicationController all_entry_ids = Array.wrap(params[:all_entry_ids]).reject(&:blank?) remaining_ids = all_entry_ids - [ entry.id.to_s ] - Entry.where(id: entry.id).bulk_update!({ category_id: category.id }) + Current.accessible_entries.where(id: entry.id).bulk_update!({ category_id: category.id }) remaining_entries = uncategorized_entries_for(remaining_ids) remaining_ids = remaining_entries.map { |e| e.id.to_s } @@ -109,7 +109,7 @@ class Transactions::CategorizesController < ApplicationController else streams << turbo_stream.replace("categorize_remaining", partial: "transactions/categorizes/remaining_count", - locals: { total_uncategorized: Entry.uncategorized_count(Current.accessible_entries) }) + locals: { total_uncategorized: uncategorized_count }) streams << turbo_stream.replace("categorize_group_summary", partial: "transactions/categorizes/group_summary", locals: { entries: remaining_entries }) @@ -119,13 +119,16 @@ class Transactions::CategorizesController < ApplicationController private + def uncategorized_count + Current.accessible_entries.uncategorized_transactions.count + end + def uncategorized_entries_for(ids) return [] if ids.blank? Current.accessible_entries .excluding_split_parents .where(id: ids) - .joins("INNER JOIN transactions ON transactions.id = entries.entryable_id AND entries.entryable_type = 'Transaction'") - .where(transactions: { category_id: nil }) + .uncategorized_transactions .to_a end end diff --git a/app/controllers/transactions_controller.rb b/app/controllers/transactions_controller.rb index 876e7d848..6548d26ed 100644 --- a/app/controllers/transactions_controller.rb +++ b/app/controllers/transactions_controller.rb @@ -52,7 +52,7 @@ class TransactionsController < ApplicationController Set.new end - @uncategorized_count = Current.family.uncategorized_transaction_count + @uncategorized_count = Current.accessible_entries.uncategorized_transactions.count # Load projected recurring transactions for next 10 days @projected_recurring = Current.family.recurring_transactions diff --git a/app/models/entry.rb b/app/models/entry.rb index 2a3de89ad..48b216f36 100644 --- a/app/models/entry.rb +++ b/app/models/entry.rb @@ -91,19 +91,16 @@ class Entry < ApplicationRecord joins(:account).where(accounts: { family_id: family.id }) end - # Counts uncategorized, non-transfer entries in the given scope. - # Used by the Quick Categorize Wizard to show the remaining count. - # @param entries [ActiveRecord::Relation] pre-scoped entries (caller controls authorization) - def self.uncategorized_count(entries) - entries - .joins(:account) + # Uncategorized, non-transfer transaction entries on draft or active accounts. + # Caller is responsible for scoping to accessible entries before applying this scope. + scope :uncategorized_transactions, -> { + joins(:account) .joins("INNER JOIN transactions ON transactions.id = entries.entryable_id AND entries.entryable_type = 'Transaction'") .where(accounts: { status: %w[draft active] }) .where(transactions: { category_id: nil }) .where.not(transactions: { kind: Transaction::TRANSFER_KINDS }) .where(entries: { excluded: false }) - .count - end + } # Returns uncategorized, non-transfer entries whose name matches the given filter string. # Used by the Quick Categorize Wizard to preview which transactions a rule would affect. @@ -111,13 +108,8 @@ class Entry < ApplicationRecord def self.uncategorized_matching(entries, filter, transaction_type = nil) sanitized = sanitize_sql_like(filter.gsub(/\s+/, " ").strip) scope = entries - .joins(:account) - .joins("INNER JOIN transactions ON transactions.id = entries.entryable_id AND entries.entryable_type = 'Transaction'") - .where(accounts: { status: %w[draft active] }) - .where(transactions: { category_id: nil }) - .where.not(transactions: { kind: Transaction::TRANSFER_KINDS }) - .where(entries: { excluded: false }) - .where("BTRIM(REGEXP_REPLACE(entries.name, '[[:space:]]+', ' ', 'g')) ILIKE ?", "%#{sanitized}%") + .uncategorized_transactions + .where("BTRIM(REGEXP_REPLACE(entries.name, '[[:space:]]+', ' ', 'g')) ILIKE ?", "%#{sanitized}%") scope = case transaction_type when "income" then scope.where("entries.amount < 0") diff --git a/app/models/family.rb b/app/models/family.rb index 2f7ad1b50..f5eceb93f 100644 --- a/app/models/family.rb +++ b/app/models/family.rb @@ -144,17 +144,6 @@ class Family < ApplicationRecord AutoMerchantDetector.new(self, transaction_ids: transaction_ids).auto_detect end - def uncategorized_transaction_count - Transaction - .joins("INNER JOIN entries ON entries.entryable_id = transactions.id AND entries.entryable_type = 'Transaction'") - .joins("INNER JOIN accounts ON accounts.id = entries.account_id") - .where(accounts: { family_id: id, status: %w[draft active] }) - .where(transactions: { category_id: nil }) - .where.not(transactions: { kind: Transaction::TRANSFER_KINDS }) - .where(entries: { excluded: false }) - .count - end - def balance_sheet(user: Current.user) BalanceSheet.new(self, user: user) end diff --git a/app/models/transaction/grouper/by_merchant_or_name.rb b/app/models/transaction/grouper/by_merchant_or_name.rb index 3618f65de..8a80a8388 100644 --- a/app/models/transaction/grouper/by_merchant_or_name.rb +++ b/app/models/transaction/grouper/by_merchant_or_name.rb @@ -22,12 +22,7 @@ class Transaction::Grouper::ByMerchantOrName < Transaction::Grouper def uncategorized_entries entries - .joins(:account) - .joins("INNER JOIN transactions ON transactions.id = entries.entryable_id AND entries.entryable_type = 'Transaction'") - .where(accounts: { status: %w[draft active] }) - .where(transactions: { category_id: nil }) - .where.not(transactions: { kind: Transaction::TRANSFER_KINDS }) - .where(entries: { excluded: false }) + .uncategorized_transactions .includes(entryable: :merchant) .order(entries: { date: :desc }) end diff --git a/app/views/transactions/categorizes/_entry_row.html.erb b/app/views/transactions/categorizes/_entry_row.html.erb index 5321079bc..daba95b7f 100644 --- a/app/views/transactions/categorizes/_entry_row.html.erb +++ b/app/views/transactions/categorizes/_entry_row.html.erb @@ -7,7 +7,7 @@ data-action="change->categorize#uncheckRule"> <%= entry.name %> <%= l(entry.date, format: :short) %> - "> + "> <%= format_money(entry.amount_money.abs) %> <%= select_tag "category_id", diff --git a/app/views/transactions/categorizes/_group_summary.html.erb b/app/views/transactions/categorizes/_group_summary.html.erb index eeaa0dc14..0477fe7e1 100644 --- a/app/views/transactions/categorizes/_group_summary.html.erb +++ b/app/views/transactions/categorizes/_group_summary.html.erb @@ -2,6 +2,6 @@

<%= t("transactions.categorizes.show.transaction_count", count: entries.size) %> · - <%= format_money(entries.sum { |e| e.amount_money.abs }) %> + <%= format_money(entries.sum { |e| e.amount_money.abs }) %>

<% end %> diff --git a/app/views/transactions/categorizes/show.html.erb b/app/views/transactions/categorizes/show.html.erb index 59d49f61b..e5cb1f20e 100644 --- a/app/views/transactions/categorizes/show.html.erb +++ b/app/views/transactions/categorizes/show.html.erb @@ -29,7 +29,7 @@

<%= t(".transaction_count", count: @group.entries.size) %> · - <%= format_money(@group.entries.sum { |e| e.amount_money.abs }) %> + <%= format_money(@group.entries.sum { |e| e.amount_money.abs }) %>

<% end %>