mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 12:04:08 +00:00
Pending detection, FX metadata, Pending UI badge. (#374)
* - Add support for `SIMPLEFIN_INCLUDE_PENDING` to control pending behavior via ENV. - Enhance debug logging for SimpleFin API requests and raw payloads. - Refine pending flag handling in `SimplefinEntry::Processor` based on provider data and inferred conditions. - Improve FX metadata processing for transactions with currency mismatches. - Add new tests for pending detection, FX metadata, and edge cases involving `posted` values. - Add pending indicator UI to transaction view. * Document pending transaction detection, storage, and UI behavior for SimpleFIN and Plaid integrations. Add debug flags for troubleshooting. * Add `pending?` method to `Transaction` model, refactor UI indicator, and centralize SimpleFIN configuration - Introduced `pending?` method in `Transaction` for unified pending state detection. - Refactored transaction pending indicator in the UI to use `pending?` method. - Centralized SimpleFIN configuration in initializer with ENV-backed toggles. - Updated tests for `pending?` behavior and clarified docs for pending detection logic * Add SimpleFIN debug and runtime flags to `.env.local.example` and `.env.test.example` - Introduced `SIMPLEFIN_INCLUDE_PENDING` and `SIMPLEFIN_DEBUG_RAW` flags for controlling pending behavior and debugging. - Updated example environment files with descriptions for new configuration options. * Normalize formatting for `SIMPLEFIN_INCLUDE_PENDING` and `SIMPLEFIN_DEBUG_RAW` flags in `.env.local.example` and `.env.test.example`. --------- Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
This commit is contained in:
@@ -53,4 +53,90 @@ class SimplefinEntry::ProcessorTest < ActiveSupport::TestCase
|
||||
assert_equal "Order #1234", sf["description"]
|
||||
assert_equal({ "category" => "restaurants", "check_number" => nil }, sf["extra"])
|
||||
end
|
||||
test "flags pending transaction when posted is nil and transacted_at present" do
|
||||
tx = {
|
||||
id: "tx_pending_1",
|
||||
amount: "-20.00",
|
||||
currency: "USD",
|
||||
payee: "Coffee Shop",
|
||||
description: "Latte",
|
||||
memo: "Morning run",
|
||||
posted: nil,
|
||||
transacted_at: (Date.today - 3).to_s
|
||||
}
|
||||
|
||||
SimplefinEntry::Processor.new(tx, simplefin_account: @simplefin_account).process
|
||||
|
||||
entry = @account.entries.find_by!(external_id: "simplefin_tx_pending_1", source: "simplefin")
|
||||
sf = entry.transaction.extra.fetch("simplefin")
|
||||
|
||||
assert_equal true, sf["pending"], "expected pending flag to be true"
|
||||
end
|
||||
|
||||
test "captures FX metadata when tx currency differs from account currency" do
|
||||
# Account is USD from setup; use EUR for tx
|
||||
t_date = (Date.today - 5)
|
||||
p_date = Date.today
|
||||
|
||||
tx = {
|
||||
id: "tx_fx_1",
|
||||
amount: "-42.00",
|
||||
currency: "EUR",
|
||||
payee: "Boulangerie",
|
||||
description: "Croissant",
|
||||
posted: p_date.to_s,
|
||||
transacted_at: t_date.to_s
|
||||
}
|
||||
|
||||
SimplefinEntry::Processor.new(tx, simplefin_account: @simplefin_account).process
|
||||
|
||||
entry = @account.entries.find_by!(external_id: "simplefin_tx_fx_1", source: "simplefin")
|
||||
sf = entry.transaction.extra.fetch("simplefin")
|
||||
|
||||
assert_equal "EUR", sf["fx_from"]
|
||||
assert_equal t_date.to_s, sf["fx_date"], "fx_date should prefer transacted_at"
|
||||
end
|
||||
test "flags pending when provider pending flag is true (even if posted provided)" do
|
||||
tx = {
|
||||
id: "tx_pending_flag_1",
|
||||
amount: "-9.99",
|
||||
currency: "USD",
|
||||
payee: "Test Store",
|
||||
description: "Auth",
|
||||
memo: "",
|
||||
posted: Date.today.to_s, # provider says pending=true should still flag
|
||||
transacted_at: (Date.today - 1).to_s,
|
||||
pending: true
|
||||
}
|
||||
|
||||
SimplefinEntry::Processor.new(tx, simplefin_account: @simplefin_account).process
|
||||
|
||||
entry = @account.entries.find_by!(external_id: "simplefin_tx_pending_flag_1", source: "simplefin")
|
||||
sf = entry.transaction.extra.fetch("simplefin")
|
||||
assert_equal true, sf["pending"], "expected pending flag to be true when provider sends pending=true"
|
||||
end
|
||||
|
||||
test "posted==0 treated as missing, entry uses transacted_at date and flags pending" do
|
||||
# Simulate provider sending epoch-like zeros for posted and an integer transacted_at
|
||||
t_epoch = (Date.today - 2).to_time.to_i
|
||||
tx = {
|
||||
id: "tx_pending_zero_posted_1",
|
||||
amount: "-6.48",
|
||||
currency: "USD",
|
||||
payee: "Dunkin'",
|
||||
description: "DUNKIN #358863",
|
||||
memo: "",
|
||||
posted: 0,
|
||||
transacted_at: t_epoch,
|
||||
pending: true
|
||||
}
|
||||
|
||||
SimplefinEntry::Processor.new(tx, simplefin_account: @simplefin_account).process
|
||||
|
||||
entry = @account.entries.find_by!(external_id: "simplefin_tx_pending_zero_posted_1", source: "simplefin")
|
||||
# For depository accounts, processor prefers posted, then transacted; posted==0 should be treated as missing
|
||||
assert_equal Time.at(t_epoch).to_date, entry.date, "expected entry.date to use transacted_at when posted==0"
|
||||
sf = entry.transaction.extra.fetch("simplefin")
|
||||
assert_equal true, sf["pending"], "expected pending flag to be true when posted==0 and/or pending=true"
|
||||
end
|
||||
end
|
||||
|
||||
21
test/models/transaction_test.rb
Normal file
21
test/models/transaction_test.rb
Normal file
@@ -0,0 +1,21 @@
|
||||
require "test_helper"
|
||||
|
||||
class TransactionTest < ActiveSupport::TestCase
|
||||
test "pending? is true when extra.simplefin.pending is truthy" do
|
||||
transaction = Transaction.new(extra: { "simplefin" => { "pending" => true } })
|
||||
|
||||
assert transaction.pending?
|
||||
end
|
||||
|
||||
test "pending? is true when extra.plaid.pending is truthy" do
|
||||
transaction = Transaction.new(extra: { "plaid" => { "pending" => "true" } })
|
||||
|
||||
assert transaction.pending?
|
||||
end
|
||||
|
||||
test "pending? is false when no provider pending metadata is present" do
|
||||
transaction = Transaction.new(extra: { "plaid" => { "pending" => false } })
|
||||
|
||||
assert_not transaction.pending?
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user