Exclude pending transactions from balances - #2897
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughPending entries are excluded from balance date and currency calculations, investment history start dates, and converted-entry caching. Tests verify that posted transactions and trade entries remain included. ChangesPending balance entry handling
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: af426047b8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| .merge(Account.included_in_reports) | ||
| .where(entries: { entryable_type: "Transaction", excluded: false, date: @period.date_range }) | ||
| .where.not(kind: Transaction::BUDGET_EXCLUDED_KINDS) | ||
| .without_matched_transfer |
There was a problem hiding this comment.
Keep investment contributions in reports breakdown
With the default preference (treat_investment_contributions_as_transfers? false), IncomeStatement now keeps the matched brokerage outflow via cash_flow_transfer_sql, so the report summary totals include investment contributions. This scope unconditionally uses without_matched_transfer, and the export helpers copy the same filter, so a confirmed transfer to an investment account is dropped from the transactions breakdown/CSV while the expense total still includes it; use the cash-flow transfer filter unless the user has opted out.
Useful? React with 👍 / 👎.
0f49b65 to
073bf22
Compare
073bf22 to
2605857
Compare
jjmata
left a comment
There was a problem hiding this comment.
Overview
This PR extends the existing Entry.excluding_pending / Transaction.excluding_pending scopes (already used by income_statement.rb, goal.rb, family.rb, transaction/search.rb) into the balance materialization pipeline, so provider-marked pending transactions no longer contribute to materialized Balance rows, multi-currency detection, calc boundaries, or linked-investment history trimming.
Files touched:
Balance::BaseCalculator#calculation_start_date— bounds the earliest materialized date on posted entries onlyBalance::ForwardCalculator#multi_currency_account?/#calc_end_date— ignores pending entries for the full-recalc trigger and the end-of-window dateBalance::LinkedInvestmentSeriesNormalizer— trims linked-investment history start dates using posted activity onlyBalance::SyncCache#converted_entries— the central per-date entry cache used by bothForwardCalculatorandReverseCalculator(viaflows_for_date/get_entries) now excludes pending entries
Code quality / correctness
- Good central fix: routing the actual flow/balance math through
Balance::SyncCache#converted_entriesmeans bothBalance::ForwardCalculatorandBalance::ReverseCalculatorpick up the exclusion "for free" viasync_cache.get_entries/get_valuation, since both inheritflows_for_date/derive_cash_balance/derive_non_cash_balancefromBalance::BaseCalculator. The remaining call sites (calculation_start_date,multi_currency_account?,calc_end_date, the linked-investment normalizer) are boundary-detection queries that hitaccount.entriesdirectly and correctly needed the same fix independently — nice catch that these weren't just relying on the cache. - Reuses existing provider-agnostic infra: no new pending-detection logic was introduced; it all flows through
Transaction::PENDING_PROVIDERS/PENDING_CHECK_SQL, which already covers simplefin/plaid/lunchflow/enable_banking/akahu/up/mercury/redbark. This keeps balance exclusion consistent with theTransaction#pending?UI badge and avoids the risk of drift between "what counts as pending" in different places. entryable_type != 'Transaction'guard preserved:excluding_pending(Entry-level) correctly leaves Trades, Valuations, etc. untouched — confirmed via the newsync_cache_test.rbcase that aTradeentry survives the filter.- No N+1 / correctness risk: all changed call sites are single aggregate/EXISTS SQL queries (
.minimum,.maximum,.exists?, or a subquery-filteredWHERE), not per-record loads, so this doesn't introduce N+1s. Thecalc_end_dateswitch from.order(:date).last&.dateto.maximum(:date)(and the same forholdings) is a nice incidental efficiency win (aggregate instead of full-row fetch + sort), though it's an unrelated optimization riding along with the pending-exclusion fix on the same line — worth calling out separately in the commit message/description for future git-blame clarity, but not blocking. - Convention adherence looks solid: logic lives in
app/models/balance/*(no new service objects), nocurrent_user/current_familyusage needed here (no controller changes), no new dependencies, and no user-facing strings requiring i18n updates.
Test coverage
Tests are minimal, focused, and use Minitest + the existing create_account_with_ledger/fixture helpers (no FactoryBot/RSpec), consistent with repo conventions:
forward_calculator_test.rb: verifies a pending transaction is excluded from bothbalanceandcash_inflows, and its date doesn't appear in the output series.linked_investment_series_normalizer_test.rb(new): verifiescommon_supported_history_start_dateskips a pending Plaid transaction in favor of the posted one.sync_cache_test.rb: verifiesconverted_entriesdrops a pending transaction while keeping a posted transaction and aTrade.
Two gaps worth considering (non-blocking, but would tighten coverage):
- No direct test for
Balance::BaseCalculator#calculation_start_datein the scenario where the oldest entry is pending (i.e., confirming it correctly falls back toopening_anchor_date/next posted entry rather than the pending entry's date). - No test for
ForwardCalculator#multi_currency_account?confirming a pending foreign-currency entry no longer forces a full recalculation on an otherwise single-currency account — this is a meaningful behavior change (avoids unnecessary full recalcs) that isn't directly asserted.
Risks / things to double check before merge
- PR description notes tests couldn't be run locally (missing Ruby 3.4.9); please confirm CI is green, especially given
Balance::Materializer#purge_stale_balancesdepends oncalculation_start_date/calc_end_datefor its purge bounds — worth watching CI for any interaction with balance purging on accounts that have only pending entries near the boundary. Balance::ReverseCalculatorwasn't directly touched or tested, but appears correctly covered transitively throughBalance::BaseCalculator+Balance::SyncCache. Worth a quick manual sanity check (or a follow-up test) since reverse sync is a distinct code path from forward.
Overall this is a well-scoped, correctly-targeted fix that reuses existing provider-agnostic pending infrastructure rather than reinventing it, and the tests exercise the actual regression being fixed. Nice work.
Generated by Claude Code
659b3d4 to
48c336d
Compare
Summary
Tests
git diff --check(pass)Summary by CodeRabbit
Bug Fixes
Tests