mirror of
https://github.com/we-promise/sure.git
synced 2026-04-07 14:31:25 +00:00
UI Suggestions for Account Types in Setup Modal + Stats-Based Inactive Handling (#368)
* - Add tests for `Simplefin::AccountTypeMapper` and `AccountSimplefinCreation` - Implement `Simplefin::AccountTypeMapper` for account type inference with fallback-only logic - Enhance inactive state handling for `SimplefinItem::Importer` - Improve subtype selection handling in views with confidence-based inference * Remove unnecessary `.presence` check for `openai_uri_base` in hostings settings * Refine zero balance detection logic in `SimplefinItem::Importer` and add regression test for missing balances scenario * Enhance account type and subtype inference logic with explicit investment subtype mapping, improved regex handling, and institution-based credit card detection * Refine retirement subtype mapping in `AccountTypeMapper` tests with explicit case-based assertions * Expand `AccountTypeMapper` investment subtype mapping to include `403b` and `tsp` with updated regex definitions * Remove unused `retirement_hint?` method in `AccountTypeMapper` to simplify codebase --------- Co-authored-by: Josh Waldrep <joshua.waldrep5+github@gmail.com>
This commit is contained in:
38
test/models/account_simplefin_creation_test.rb
Normal file
38
test/models/account_simplefin_creation_test.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
require "test_helper"
|
||||
|
||||
class AccountSimplefinCreationTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@family = families(:dylan_family)
|
||||
@item = SimplefinItem.create!(family: @family, name: "SF Conn", access_url: "https://example.com/access")
|
||||
end
|
||||
|
||||
test "requires explicit account_type at creation" do
|
||||
sfa = SimplefinAccount.create!(
|
||||
simplefin_item: @item,
|
||||
name: "Brokerage",
|
||||
account_id: "acct_1",
|
||||
currency: "USD",
|
||||
account_type: "investment",
|
||||
current_balance: 1000
|
||||
)
|
||||
|
||||
assert_raises(ArgumentError) do
|
||||
Account.create_from_simplefin_account(sfa, nil)
|
||||
end
|
||||
end
|
||||
|
||||
test "uses provided account_type without inference" do
|
||||
sfa = SimplefinAccount.create!(
|
||||
simplefin_item: @item,
|
||||
name: "My Loan",
|
||||
account_id: "acct_2",
|
||||
currency: "USD",
|
||||
account_type: "loan",
|
||||
current_balance: -5000
|
||||
)
|
||||
|
||||
account = Account.create_from_simplefin_account(sfa, "Loan")
|
||||
|
||||
assert_equal "Loan", account.accountable_type
|
||||
end
|
||||
end
|
||||
40
test/models/simplefin/account_type_mapper_test.rb
Normal file
40
test/models/simplefin/account_type_mapper_test.rb
Normal file
@@ -0,0 +1,40 @@
|
||||
require "test_helper"
|
||||
|
||||
class Simplefin::AccountTypeMapperTest < ActiveSupport::TestCase
|
||||
test "holdings present implies Investment" do
|
||||
inf = Simplefin::AccountTypeMapper.infer(name: "Vanguard Brokerage", holdings: [ { symbol: "VTI" } ])
|
||||
assert_equal "Investment", inf.accountable_type
|
||||
assert_nil inf.subtype
|
||||
end
|
||||
|
||||
test "explicit retirement tokens map to exact subtypes" do
|
||||
cases = {
|
||||
"My Roth IRA" => "roth_ira",
|
||||
"401k Fidelity" => "401k"
|
||||
}
|
||||
cases.each do |name, expected_subtype|
|
||||
inf = Simplefin::AccountTypeMapper.infer(name: name, holdings: [ { symbol: "VTI" } ])
|
||||
assert_equal "Investment", inf.accountable_type
|
||||
assert_equal expected_subtype, inf.subtype
|
||||
end
|
||||
end
|
||||
|
||||
test "credit card names map to CreditCard" do
|
||||
[ "Chase Credit Card", "VISA Card", "CREDIT" ] .each do |name|
|
||||
inf = Simplefin::AccountTypeMapper.infer(name: name)
|
||||
assert_equal "CreditCard", inf.accountable_type
|
||||
end
|
||||
end
|
||||
|
||||
test "loan-like names map to Loan" do
|
||||
[ "Mortgage", "Student Loan", "HELOC", "Line of Credit" ].each do |name|
|
||||
inf = Simplefin::AccountTypeMapper.infer(name: name)
|
||||
assert_equal "Loan", inf.accountable_type
|
||||
end
|
||||
end
|
||||
|
||||
test "default is Depository" do
|
||||
inf = Simplefin::AccountTypeMapper.infer(name: "Everyday Checking")
|
||||
assert_equal "Depository", inf.accountable_type
|
||||
end
|
||||
end
|
||||
62
test/models/simplefin_item/importer_inactive_test.rb
Normal file
62
test/models/simplefin_item/importer_inactive_test.rb
Normal file
@@ -0,0 +1,62 @@
|
||||
require "test_helper"
|
||||
|
||||
class SimplefinItem::ImporterInactiveTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@family = families(:dylan_family)
|
||||
@item = SimplefinItem.create!(family: @family, name: "SF Conn", access_url: "https://example.com/access")
|
||||
@sync = Sync.create!(syncable: @item)
|
||||
end
|
||||
|
||||
def importer
|
||||
@importer ||= SimplefinItem::Importer.new(@item, simplefin_provider: mock(), sync: @sync)
|
||||
end
|
||||
|
||||
test "marks inactive when payload indicates closed or hidden" do
|
||||
account_data = { id: "a1", name: "Old Checking", balance: 0, currency: "USD", closed: true }
|
||||
importer.send(:import_account, account_data)
|
||||
|
||||
stats = @sync.reload.sync_stats
|
||||
assert stats.dig("inactive", "a1"), "should be inactive when closed flag present"
|
||||
end
|
||||
|
||||
test "marks inactive after three consecutive zero runs with no holdings" do
|
||||
account_data = { id: "a2", name: "Dormant", balance: 0, "available-balance": 0, currency: "USD" }
|
||||
|
||||
2.times { importer.send(:import_account, account_data) }
|
||||
stats = @sync.reload.sync_stats
|
||||
assert_equal 2, stats.dig("zero_runs", "a2"), "should count zero runs"
|
||||
assert_equal false, stats.dig("inactive", "a2"), "should not be inactive before threshold"
|
||||
|
||||
importer.send(:import_account, account_data)
|
||||
stats = @sync.reload.sync_stats
|
||||
assert_equal true, stats.dig("inactive", "a2"), "should be inactive at threshold"
|
||||
end
|
||||
|
||||
test "resets zero_runs_count and inactive when activity returns" do
|
||||
account_data = { id: "a3", name: "Dormant", balance: 0, "available-balance": 0, currency: "USD" }
|
||||
3.times { importer.send(:import_account, account_data) }
|
||||
stats = @sync.reload.sync_stats
|
||||
assert_equal true, stats.dig("inactive", "a3")
|
||||
|
||||
# Activity returns: non-zero balance or holdings
|
||||
active_data = { id: "a3", name: "Dormant", balance: 10, currency: "USD" }
|
||||
importer.send(:import_account, active_data)
|
||||
stats = @sync.reload.sync_stats
|
||||
assert_equal 0, stats.dig("zero_runs", "a3")
|
||||
assert_equal false, stats.dig("inactive", "a3")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
# Additional regression: no balances present should not increment zero_runs or mark inactive
|
||||
class SimplefinItem::ImporterInactiveTest < ActiveSupport::TestCase
|
||||
test "does not count zero run when both balances are missing and no holdings" do
|
||||
account_data = { id: "a4", name: "Unknown", currency: "USD" } # no balance keys, no holdings
|
||||
|
||||
importer.send(:import_account, account_data)
|
||||
stats = @sync.reload.sync_stats
|
||||
|
||||
assert_equal 0, stats.dig("zero_runs", "a4").to_i
|
||||
assert_equal false, stats.dig("inactive", "a4")
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user