mirror of
https://github.com/we-promise/sure.git
synced 2026-08-04 08:02:15 +00:00
* 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>
80 lines
3.2 KiB
Ruby
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
|