Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions app/models/entry_search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,16 +62,15 @@ def apply_status_filter(scope, statuses)
return scope unless statuses.present?
return scope if statuses.uniq.sort == %w[confirmed pending] # Both selected = no filter

# Source the pending check from Transaction::PENDING_CHECK_SQL (aliased to
# "t") so every provider in PENDING_PROVIDERS is covered. Previously this
# hardcoded only simplefin/plaid/lunchflow, dropping enable_banking.
pending_condition = <<~SQL.squish
entries.entryable_type = 'Transaction'
AND EXISTS (
SELECT 1 FROM transactions t
WHERE t.id = entries.entryable_id
AND (
(t.extra -> 'simplefin' ->> 'pending')::boolean = true
OR (t.extra -> 'plaid' ->> 'pending')::boolean = true
OR (t.extra -> 'lunchflow' ->> 'pending')::boolean = true
)
AND (#{Transaction::PENDING_CHECK_SQL})
)
SQL

Expand All @@ -80,11 +79,7 @@ def apply_status_filter(scope, statuses)
OR NOT EXISTS (
SELECT 1 FROM transactions t
WHERE t.id = entries.entryable_id
AND (
(t.extra -> 'simplefin' ->> 'pending')::boolean = true
OR (t.extra -> 'plaid' ->> 'pending')::boolean = true
OR (t.extra -> 'lunchflow' ->> 'pending')::boolean = true
)
AND (#{Transaction::PENDING_CHECK_SQL})
)
SQL

Expand Down
19 changes: 5 additions & 14 deletions app/models/transaction/search.rb
Original file line number Diff line number Diff line change
Expand Up @@ -196,23 +196,14 @@ def apply_status_filter(query, statuses)
return query unless statuses.present?
return query if statuses.uniq.sort == [ "confirmed", "pending" ] # Both selected = no filter

pending_condition = <<~SQL.squish
(transactions.extra -> 'simplefin' ->> 'pending')::boolean = true
OR (transactions.extra -> 'plaid' ->> 'pending')::boolean = true
OR (transactions.extra -> 'lunchflow' ->> 'pending')::boolean = true
SQL

confirmed_condition = <<~SQL.squish
(transactions.extra -> 'simplefin' ->> 'pending')::boolean IS DISTINCT FROM true
AND (transactions.extra -> 'plaid' ->> 'pending')::boolean IS DISTINCT FROM true
AND (transactions.extra -> 'lunchflow' ->> 'pending')::boolean IS DISTINCT FROM true
SQL

# Delegate to the model scopes so the provider list stays sourced from
# Transaction::PENDING_PROVIDERS. Previously this method hardcoded only
# simplefin/plaid/lunchflow, silently dropping enable_banking transactions.
case statuses.sort
when [ "pending" ]
query.where(pending_condition)
query.pending
when [ "confirmed" ]
query.where(confirmed_condition)
query.excluding_pending
else
query
end
Expand Down
24 changes: 24 additions & 0 deletions test/models/account/entry_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,30 @@ class EntryTest < ActiveSupport::TestCase
assert_equal 0, family.entries.search(params).size
end

test "status filter matches pending transactions for every supported provider via EntrySearch" do
family = families(:empty)
account = family.accounts.create! name: "Test", balance: 0, currency: "USD", accountable: Depository.new

confirmed = create_transaction(account: account, amount: 50, kind: "standard")

pending_by_provider = Transaction::PENDING_PROVIDERS.index_with do |provider|
entry = create_transaction(account: account, amount: 50, kind: "standard")
entry.entryable.update!(extra: { provider => { "pending" => true } })
entry.id
end

pending_ids = family.entries.search(status: [ "pending" ]).pluck(:id)
confirmed_ids = family.entries.search(status: [ "confirmed" ]).pluck(:id)

pending_by_provider.each do |provider, entry_id|
assert_includes pending_ids, entry_id, "#{provider} pending entry should match the pending filter"
assert_not_includes confirmed_ids, entry_id, "#{provider} pending entry should be excluded from the confirmed filter"
end

assert_includes confirmed_ids, confirmed.id
assert_not_includes pending_ids, confirmed.id
end

test "visible scope only returns entries from visible accounts" do
# Create transactions for all account types
visible_transaction = create_transaction(account: accounts(:depository), name: "Visible transaction")
Expand Down
24 changes: 24 additions & 0 deletions test/models/transaction/search_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -646,4 +646,28 @@ class Transaction::SearchTest < ActiveSupport::TestCase
assert_equal Money.new(0, @family.currency), totals.transfer_inflow_money
assert_equal Money.new(0, @family.currency), totals.transfer_outflow_money
end

test "status filter matches pending transactions for every supported provider" do
confirmed = create_transaction(account: @checking_account, amount: 100, kind: "standard")

# One pending transaction per provider in PENDING_PROVIDERS. Regression for the
# status filter only checking simplefin/plaid/lunchflow and silently dropping
# enable_banking pending transactions.
pending_by_provider = Transaction::PENDING_PROVIDERS.index_with do |provider|
entry = create_transaction(account: @checking_account, amount: 100, kind: "standard")
entry.entryable.update!(extra: { provider => { "pending" => true } })
entry.entryable.id
end

pending_ids = Transaction::Search.new(@family, filters: { status: [ "pending" ] }).transactions_scope.pluck(:id)
confirmed_ids = Transaction::Search.new(@family, filters: { status: [ "confirmed" ] }).transactions_scope.pluck(:id)

pending_by_provider.each do |provider, txn_id|
assert_includes pending_ids, txn_id, "#{provider} pending txn should match the pending filter"
assert_not_includes confirmed_ids, txn_id, "#{provider} pending txn should be excluded from the confirmed filter"
end

assert_includes confirmed_ids, confirmed.entryable.id
assert_not_includes pending_ids, confirmed.entryable.id
end
end