Files
sure/app/models
5825ae81cf Align uncategorized Transactions filter with dashboard aggregate (fix #2592) (#3293)
* Align uncategorized filter with dashboard aggregate (fix #2592)

The Transactions page's 'Uncategorized' category bucket excluded
Transaction::TRANSFER_KINDS, but the dashboard cashflow widget computes
its Uncategorized figure from IncomeStatement::Totals which excludes
Transaction::BUDGET_EXCLUDED_KINDS.

The two sets disagree on loan_payment and investment_contribution:
those kinds were hidden from the list while their value was still
counted in the widget, so the widget's figure could not be reproduced
from the Transactions page.

This changes the uncategorized exclusion in Transaction::Search#
apply_category_filter to match BUDGET_EXCLUDED_KINDS exactly — the same
set the dashboard aggregate excludes — so the widget and the list
always agree. The type filter (apply_type_filter) is left using
TRANSFER_KINDS, which is its correct semantic for the expense/
income/transfer UI switch.

Regression tests:
- search_test.rb: uncategorized filter lists loan_payment +
  investment_contribution (bites before the fix: asserts inclusion on
  two kinds that were being excluded).
- search_test.rb: funds_movement (a member of BUDGET_EXCLUDED_KINDS) is
  still excluded from uncategorized, guarding against over-broadening.

Fixes https://github.com/we-promise/sure/issues/2592

* docs: add docstrings to Transaction::Search methods (PR #3293)

Add comprehensive docstrings to all public and private methods in the
Transaction::Search class to meet 80%+ coverage requirement:

- Add docstring to initialize method
- Add docstring to transactions_scope
- Add docstring to totals method
- Add docstring to cache_key_base
- Add docstring to apply_active_accounts_filter
- Add docstring to apply_category_filter (method touched in PR)
- Add docstring to apply_type_filter
- Add docstring to apply_merchant_filter
- Add docstring to apply_tag_filter
- Add docstring to apply_status_filter

Addresses CodeRabbit docstring coverage requirement.

* fix: preserve one-time transactions in uncategorized searches (PR #3293)

Address Codex feedback: one-time transactions should remain visible in
uncategorized searches since users can categorize them. The previous
approach using BUDGET_EXCLUDED_KINDS excluded one_time, making them
undiscoverable.

Solution: Use a minimal exclusion set for uncategorized that only
excludes pure transfer-like kinds (funds_movement, cc_payment).
This preserves:
- one_time transactions (user-marked as one-time, still categorizable)
- loan_payment transactions (legitimate uncategorized entries)
- investment_contribution transactions (legitimate uncategorized entries)

While still aligning with dashboard by excluding inter-account transfers.

Fixes https://github.com/we-promise/sure/issues/2592
Addresses PR #3293 feedback

* fix: bump totals cache key to avoid stale post-deploy mismatch (#2592)

CodeRabbit flagged a moderate merge risk: Transaction::Search#totals is
cached under a key that only reflects filter *parameters* and data
changes (entries_cache_version), not application code changes. Since
this PR changes which kinds count as "uncategorized," a totals entry
cached before deploy would keep being served after deploy (same
cache_key_base, same family, same filters, no new entries yet),
disagreeing with the Transactions page list -- which reads
transactions_scope directly and isn't cached -- until that family's
entries_cache_version next changes.

Bumping the cache key prefix from v2 to v3 invalidates every existing
totals cache entry on deploy, so the first read after release recomputes
under the new logic instead of serving stale figures.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9494Pxh4LZKnNLTGfFXPw

* fix(transactions): align uncategorized filter with dashboard exclusions

- Use Transaction::BUDGET_EXCLUDED_KINDS for consistency with dashboard
- Exclude one_time from uncategorized filter to match dashboard behavior
- Update comment to clarify alignment with dashboard uncategorized totals

Fixes disagreement between code comment, test comment, and dashboard behavior.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01A9494Pxh4LZKnNLTGfFXPw

* fix(transactions): share one uncategorized-kind list across all three surfaces

Resolves the two open review threads on #3293, which were the same finding
from opposite sides: the filter excluded BUDGET_EXCLUDED_KINDS, which also
drops one_time.

one_time is documented as "a one-time expense/income, excluded from budget
analytics" -- it is not a transfer, it is still categorizable, and excluding
it made an uncategorized one-time transaction undiscoverable through its
actual category state.

Reviewing that also surfaced a defect neither thread caught. Aligning only
Transaction::Search left Entry.uncategorized_transactions on TRANSFER_KINDS,
so the Transactions filter and the badge count / Quick Categorize wizard
disagreed on three of six kinds:

  kind                      filter      wizard
  loan_payment              included    EXCLUDED
  one_time                  EXCLUDED    included
  investment_contribution   included    EXCLUDED

That leaves #2592's actual complaint standing: the dashboard counts
uncategorized loan_payment / investment_contribution, but the wizard still
would not offer them for categorization.

Introduce Transaction::UNCATEGORIZED_EXCLUDED_KINDS (funds_movement,
cc_payment) -- the kinds that have nothing to categorize because they are
paired legs of a Transfer -- and read it from both surfaces. "Has no
category" and "counts toward the budget" are different questions; only the
former decides this list.

Bump the uncategorized badge cache key to v4, since the count's meaning
changes and the old key would otherwise survive deploy.

The dashboard still excludes one_time from budget totals by design; that
difference is intentional and now documented rather than papered over.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: jaysbeekay <jaysbeekay@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-09-08 09:15:40 +02:00
..
2026-03-25 17:47:04 +01:00
2026-09-08 00:40:00 +00:00
2026-03-25 10:50:23 +01:00
2026-03-25 10:50:23 +01:00