Files
sure/test/models/lunchflow_account_processor_test.rb
Stephen Jolly ba0e169f6b Don't persist zero balances when a provider balance fetch fails (#2617)
* fix(sync): don't persist zero balances when a provider balance fetch fails

A nil current_balance means the sync's balance fetch did not succeed
(the snapshot upsert clears it; only a successful fetch repopulates it).
The Lunchflow and Enable Banking processors coerced nil to 0 and write
it (plus a currency fallback) onto the linked account, so any transient
provider failure persists wrong data with no user-visible signal.
Instead, treat nil as no-data: skip the account update. Also stop the
Lunchflow snapshot upsert resetting an established account's currency to
USD when the accounts endpoint omits currency.

* fix(lunchflow): normalize the preserved currency in snapshot upsert

Addresses the review comment on #2617: the preserved fallback reused the
record's raw in-memory currency, so a blank value would fail the presence
validation and break import, and an invalid code would persist instead of
falling back to USD. Run it through parse_currency like the payload value.
Regression test added.

* fix(lunchflow,eb): review round 2 — failure visibility and currency parity

Addresses the three review findings on #2617:
1. Capture the Lunch Flow balance-fetch failure via DebugLogEntry (the sync
   otherwise reports success with no mention of the skip).
   This is Lunch Flow only: Enable Banking's importer already surfaces the
   failure through transactions_failed/@sync_error.
2. Apply the currency-preservation fix to Enable Banking's snapshot upsert
   (same shape as the Lunch Flow fix: parity/safety). Regression test added.
3. Label the Enable Banking processor currency assertion as a parity check —
   it also passes on main, since the reset defect was Lunch Flow-specific.
2026-07-08 08:08:10 +02:00

79 lines
2.6 KiB
Ruby

require "test_helper"
class LunchflowAccountProcessorTest < ActiveSupport::TestCase
setup do
@family = families(:dylan_family)
@item = LunchflowItem.new(family: @family, name: "Lunch Flow", api_key: "test_key")
@item.save!(validate: false)
end
test "skips the account update when current_balance is nil (failed balance fetch)" do
lf_acct = @item.lunchflow_accounts.create!(
name: "Checking",
account_id: "lf_1",
currency: "USD",
current_balance: nil
)
acct = accounts(:depository)
acct.update!(balance: 500, cash_balance: 500, currency: "GBP")
AccountProvider.create!(account: acct, provider: lf_acct)
LunchflowAccount::Processor.new(lf_acct).send(:process_account!)
acct.reload
assert_equal BigDecimal("500"), acct.balance,
"a sync whose balance fetch failed must not zero the account"
assert_equal "GBP", acct.currency,
"a sync whose balance fetch failed must not change the account currency"
end
test "still updates the account when current_balance is present" do
lf_acct = @item.lunchflow_accounts.create!(
name: "Checking",
account_id: "lf_2",
currency: "GBP",
current_balance: BigDecimal("250")
)
acct = accounts(:depository)
acct.update!(balance: 500, cash_balance: 500, currency: "GBP")
AccountProvider.create!(account: acct, provider: lf_acct)
LunchflowAccount::Processor.new(lf_acct).send(:process_account!)
assert_equal BigDecimal("250"), acct.reload.balance
end
test "snapshot upsert preserves the existing currency when the payload omits it" do
lf_acct = @item.lunchflow_accounts.create!(
name: "Checking",
account_id: "lf_3",
currency: "GBP"
)
# The real accounts endpoint carries neither balance nor currency.
lf_acct.upsert_lunchflow_snapshot!({ id: "lf_3", name: "Checking", status: "active" })
lf_acct.reload
assert_equal "GBP", lf_acct.currency,
"an established account's currency must survive a currency-less snapshot"
assert_nil lf_acct.current_balance
end
test "snapshot upsert falls back to USD when neither payload nor record has a valid currency" do
lf_acct = @item.lunchflow_accounts.create!(
name: "Checking",
account_id: "lf_4",
currency: "GBP"
)
# Simulate a record built from bad provider data (bypasses validation)
lf_acct.update_column(:currency, "")
lf_acct.upsert_lunchflow_snapshot!({ id: "lf_4", name: "Checking", status: "active" })
assert_equal "USD", lf_acct.reload.currency,
"a blank stored currency must fall through to USD, not fail validation"
end
end