Files
sure/test/lib/tasks/simplefin_prune_pending_test.rb
PrplHaz4 5fb8f4f81a Don’t re-create pending SimpleFIN transactions when pending sync is disabled (#2835)
* fix(simplefin): skip pending entries in processor when pending is disabled

When SIMPLEFIN_INCLUDE_PENDING/syncs_include_pending is off, pending rows
already stored in raw_transactions_payload were still (re)created as
entries on every sync - including ones the user manually deleted - because
the setting only affected the API request, not reprocessing of the stored
payload.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(simplefin): add rake task to prune stale pending rows from payload store

raw_transactions_payload accumulates transactions across syncs and is
never pruned, so pending rows fetched before pending inclusion was
disabled keep getting re-imported. This one-time maintenance task removes
them (dry-run by default; scope by item_id/account_id).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(simplefin): address PR #2835 review feedback on pending detection

Fix epoch-zero pending check treating non-numeric posted strings (e.g.
"unavailable") as pending via String#to_i coercion; compare against
explicit zero representations instead, matching posted_date. Dedupe the
prune_pending rake task's copy of this logic by delegating to a new
public SimplefinEntry::Processor.pending? class method. Also close a
test gap where SIMPLEFIN_INCLUDE_PENDING env var precedence over the
Setting wasn't actually exercised.

* test(simplefin): cover pending-guard precedence and add rake task tests

Add the missing mirror case for pending_enabled? precedence (env var
disabling pending over a permissive Setting) and add test coverage for
the prune_pending rake task, which previously had none: dry_run safety
default, correct pruning via the shared Processor.pending? predicate
(including the malformed-posted regression), and that it never touches
Entry/Transaction rows.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-29 16:14:55 -07:00

80 lines
3.2 KiB
Ruby

# frozen_string_literal: true
require "test_helper"
class SimplefinPrunePendingTest < ActiveSupport::TestCase
setup do
Rails.application.load_tasks unless Rake::Task.task_defined?("sure:simplefin:prune_pending")
Rake::Task["sure:simplefin:prune_pending"].reenable
@family = families(:dylan_family)
@account = accounts(:depository)
@simplefin_item = SimplefinItem.create!(
family: @family,
name: "Test SimpleFin Bank",
access_url: "https://example.com/access_token"
)
@simplefin_account = SimplefinAccount.create!(
simplefin_item: @simplefin_item,
name: "SF Checking",
account_id: "sf_acc_1",
account_type: "checking",
currency: "USD",
current_balance: 1000,
available_balance: 1000,
account: @account
)
end
test "dry_run defaults to true and leaves the payload untouched" do
payload = [
{ "id" => "tx_pending", "pending" => true, "posted" => Date.current.to_s, "transacted_at" => (Date.current - 1).to_s },
{ "id" => "tx_posted", "posted" => Date.current.to_s, "transacted_at" => (Date.current - 1).to_s }
]
@simplefin_account.update!(raw_transactions_payload: payload)
capture_io { Rake::Task["sure:simplefin:prune_pending"].invoke }
assert_equal payload, @simplefin_account.reload.raw_transactions_payload,
"dry_run must default to true and never write to raw_transactions_payload"
end
test "removes pending rows and keeps non-pending rows when dry_run=false" do
# Uses the same three shapes covered in SimplefinEntry::ProcessorTest: an explicit
# pending flag, a settled row, and a malformed non-numeric posted value that must NOT
# be swept up as pending (regression: SimplefinEntry::Processor.pending? is the single
# shared definition this task delegates to, so this also guards against the task
# reintroducing its own posted_val.to_i.zero? bug).
payload = [
{ "id" => "tx_pending", "pending" => true, "posted" => Date.current.to_s, "transacted_at" => (Date.current - 1).to_s },
{ "id" => "tx_posted", "posted" => Date.current.to_s, "transacted_at" => (Date.current - 1).to_s },
{ "id" => "tx_malformed_posted", "posted" => "unavailable", "transacted_at" => (Date.current - 1).to_s }
]
@simplefin_account.update!(raw_transactions_payload: payload)
capture_io { Rake::Task["sure:simplefin:prune_pending"].invoke(nil, nil, "false") }
remaining_ids = @simplefin_account.reload.raw_transactions_payload.map { |tx| tx["id"] }
assert_equal %w[tx_posted tx_malformed_posted], remaining_ids
end
test "never touches Entry/Transaction rows, only the raw payload cache" do
entry = @account.entries.create!(
name: "Pre-existing entry",
date: Date.current,
amount: 10,
currency: "USD",
entryable: Transaction.new
)
payload = [ { "id" => "tx_pending", "pending" => true, "posted" => Date.current.to_s, "transacted_at" => (Date.current - 1).to_s } ]
@simplefin_account.update!(raw_transactions_payload: payload)
assert_no_difference [ "Entry.count", "Transaction.count" ] do
capture_io { Rake::Task["sure:simplefin:prune_pending"].invoke(nil, nil, "false") }
end
assert entry.reload.persisted?
end
end