Commit Graph
47 Commits
Author SHA1 Message Date
Brandon fe0d27471d feat(bills): the bills pages, calendar feed and in-page AI helpers (#3202)
* feat(bills): the bills pages, calendar feed and in-page AI helpers

Second of three chunks carved out of #3083, stacked on the schema and domain
core. This is everything a user sees and clicks. The whole surface sits behind
the preview flag, so it is unreachable until someone opts in.

Pages, all under one nav entry:

- the pay run, a month calendar, the full bills table, and the paycheck planner
- a detail drawer per bill, with payment history, price changes and cost
  analytics
- create and edit flows for bills, subscriptions, installment plans and income

The overview marks pay periods inside the month, so a weekly paycheck no longer
reads as one undifferentiated month of bills. Markers appear only when income
actually subdivides the month, which means monthly and undeclared income render
exactly as before and there is no new setting to configure.

Navigation and design system:

- one preview-gated nav item shared by the desktop rail and the mobile bar
- DS::Sparkline for payment-history charts, replacing raw SVG in views
- status badges render through DS::Pill rather than hand-rolled spans
- the suggestions panel is a disclosure that remembers being collapsed, per
  device, the way privacy mode and the sidebar width already do
- every surface reflows to phone widths without horizontal scroll

Calendar feed: a signed ICS feed per family, served sessionless by token, with a
reset that revokes previously shared URLs.

In-page AI helpers: smart fill on the bill form and a smart configuration
proposal on an existing bill, each reading a bounded slice of charge history.
Provider-side prompt assembly sits behind the existing LlmConcept interface,
with an implementation for each of the two providers. These belong here rather
than with the assistant tools because they are buttons on these pages and lean
on the provider suggester, not on the tool registry.

Suite 7,776 runs green apart from the pre-existing passkey-session flake, which passes standalone. Rubocop clean, eager loading verified. The hosting guide for the feature ships here rather than with the schema, since its instructions walk pages this PR introduces.

* Render the suggested strip through DS::Disclosure

The hand-rolled details pair predates the component. The card_inset
variant is the same shape, so the strip now inherits the design system
chrome, and the persisted-disclosure controller rides along unchanged.

* Route the remaining hand-rolled chips through the design system

The subscription-state chips, rule-match chips and match-reason chips
become DS::Pill, with the state chips extracted to one shared partial so
the drawer and the summary tab stop carrying copy-pasted markup. The AI
prompt chips become DS::Button and the bills-index filter becomes
DS::SearchInput, both of which this PR already uses elsewhere for the
same shapes.

* Fix erb_lint whitespace offenses in bills views

* Address the post-ready review round

* Require a writable destination account and gate the feed on preview

* Reject an unresolvable declared account out loud
2026-09-02 02:08:58 +02:00
Shibu M 33c3f9f808 Show category hierarchy in transaction picker (#3292) 2026-08-31 21:53:08 +02:00
Thomas SteiblandJohns 0a8f93cc2d fix: localize transaction selectors in German (U4) (#3254)
Co-authored-by: Johns <19662585+Rowdy@users.noreply.github.com>
2026-08-31 07:44:51 +02:00
eb498cfa0c Feature/category hierarchy and account search (#2845)
* Add parent/child category hierarchy to all category selects; add search to account select

Category selection consistency:
- DS::Select (shared component powering the main transaction form,
  transaction edit, bulk-update, and transfer category pickers) now
  indents subcategories with a corner-down-right icon, matching the
  existing transaction-row category dropdown.
- Feed DS::Select-based category pickers with Category.alphabetically_by_hierarchy
  (parent name, then parent-before-children, then own name) so children
  render directly under their parent.
- Added Category::Group.select_options, a shared helper producing
  parent-then-child ordered options (with an indent marker) for plain
  HTML <select> elements. Used by:
  - Rule builder category condition/action selects
  - Bulk 'categorize transactions' select
  - CSV/QIF import category mapping select
- Grouped the splits category combobox and the transaction search
  category filter checklist the same way, both with the
  corner-down-right indent icon used elsewhere.

Account selection:
- Added searchable: true to the account select in the new/edit
  transaction form, matching the category and merchant selects next
  to it.

* Fix SyntaxError: 'for' is a Ruby reserved keyword

Category::Group.select_options called for(categories) as a bare method
call, but Ruby parses a bare 'for' as the start of a for..in loop
statement, not a method invocation. Qualify it as self.for(categories)
to call the class method explicitly.

Verified with 'ruby -c' on all touched .rb files and ERB.new(...).src
on all touched .erb files.

* Add test coverage for category hierarchy and account search

Model-level:
- Category::GroupTest (new): for() grouping and the new select_options
  helper (order + indent labels).
- CategoryTest: alphabetically_by_hierarchy scope ordering.
- Rule::ConditionFilter::TransactionCategoryTest (new)
- Rule::ActionExecutor::SetTransactionCategoryTest (new)
- Import::CategoryMappingTest (new): grouping + 'Add as new category'
  still prepends correctly.

Controller/integration-level (asserting actual rendered HTML order):
- SplitsControllerTest: category combobox data-value ordering.
- Transactions::CategorizesControllerTest: bulk-categorize <select>
  option ordering.
- TransactionsControllerTest:
  - search filter checkbox ordering (q[categories][])
  - new-transaction DS::Select category ordering (via trigger id +
    ancestor traversal)
  - new-transaction account select renders a search box

All new/modified test files verified with 'ruby -c' (syntax) and
cross-checked fixture names, family scoping, route helpers, and field
names against the actual fixtures/routes/views. Ruby/Bundler network
access to rubygems.org is unavailable in this sandbox, so the suite
itself has not been executed — run 'bin/rails test' before merging.

* Align with design-sure conventions: keep domain logic in component, not template

Per .cursor/rules/view_conventions.mdc ('keep domain logic out of the
views'), the parent/child hierarchy check for DS::Select items belongs
in the component class, not inline in the ERB template. DS::Select
already has this exact pattern for other per-item derived properties
(color_for, icon_for, logo_for) — added child? alongside them and
updated the template to call it instead of computing it inline.

Added test/components/DS/select_test.rb (ViewComponent::TestCase,
no rendering needed) covering child? directly: subcategory objects,
root-category objects, non-hierarchical objects (merchants), and the
include_blank placeholder item.

Also did a broader pass against the design-sure .cursor/rules to confirm
the rest of this branch's changes already comply:
- Uses Current.family (never current_family) throughout
- Uses the icon() helper exclusively, never lucide_icon directly
- No new/hardcoded colors; only existing semantic Tailwind tokens
  already used elsewhere in these same files
- No changes to sure-design-system.css / application.css
- Extended existing components/partials rather than creating new ones
  where one already existed (view_conventions.mdc component-vs-partial
  guidance)
- Test additions stay in Minitest + fixtures, avoid system tests,
  and test query-method output directly (testing.mdc)

* Address CodeRabbit review: sort category groups, tighten test assertion, move grouping out of view

* Address review: fix arrow leak in rule summaries, filter panel alignment, simplify splits ordering

* fix(pages): set breadcrumbs for changelog and feedback pages (#2889)

* fix(app): set breadcrumbs for changelog and feedback pages

* feat(test): add test to assert breadcrumbs

* fix(test): remove changes

* feat(app): update breadcrumbs to use semantic nav element

* feat(test): add breadcrumb assertions to changelog and feedback pages

* fix(app): replace breadcrumb nav element with div containing data-breadcrumbs attribute

* fix ci failures

* resolved failures

* Regenerate schema.rb from migrations

* Fix test

* Remove schema dump noise

---------

Signed-off-by: Shibu M <23173570+DataEnginr@users.noreply.github.com>
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Claude <claude@anthropic.com>
Co-authored-by: Kenrick Tandrian <60643640+KenTandrian@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-08-26 07:59:00 +02:00
3e79de5b64 perf: memoize Family#balance_sheet/investment_statement, cache transactions-index side queries (#3058)
* perf: memoize Family#balance_sheet/investment_statement, cache transactions-index side queries

The account sidebar renders on every page (mobile + desktop, 3 tabs each)
and calls Family#balance_sheet multiple times per render; neither it nor
Family#investment_statement/InvestmentStatement#current_holdings were
memoized, so each call rebuilt the underlying query from scratch. Memoize
both per-user (family sharing means different users must not share a
cached BalanceSheet/InvestmentStatement).

Also cache TransactionsController#index's uncategorized_count and
projected_recurring lookups, which run unconditionally on every request
regardless of whether the underlying data changed, using the same
entries_cache_version-keyed pattern already used elsewhere in the codebase
(e.g. Transaction::Search#totals).

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

* fix: address PR #3058 review feedback on cache invalidation and query reuse

- Invalidate transactions-index caches when the current user's AccountShare
  access changes, not just on entries/recurring updates (CodeRabbit/Codex
  flagged revoked users could see stale data for up to a day).
- Use full-precision timestamps instead of to_i in the cache keys so
  same-second updates aren't missed.
- Reuse the already-memoized investment_account_ids in
  InvestmentStatement#current_holdings instead of an extra any? query.
- Assert the rendered response instead of a controller instance variable in
  the uncategorized_count test, per CodeRabbit nitpick.

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

* fix: assert rendered response, not implementation details, in PR #3058 tests

Two CodeRabbit nitpicks from the second review round: the uncategorized-count
cache-reuse assertion matched a scope name that never appears in generated SQL
(making it vacuous), and the recurring-cache revocation test read the
controller's private @projected_recurring ivar instead of the rendered page.

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

* fix: bust transactions-index caches on entry/recurring deletion and account status change

jjmata's PR review flagged two invalidation gaps: hard-deleting an
uncategorized entry or recurring transaction left the previous max
updated_at unchanged (cache never busted), and toggling an account's
active status doesn't touch entries/AccountShare at all. Fold in
counts (like account_share_version already did) and a new
Family#accounts_status_version, and move the version helpers onto
Family/Current per the "fat models, skinny controllers" nit.

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

* fix: include merchant version in projected_recurring cache key

Editing or deleting a FamilyMerchant doesn't touch recurring_transactions,
so the cached projected-recurring list (rendered with merchant name/logo,
expires_in: 1.day) could show stale merchant data for up to a day.

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

* fix(transactions): version projected-recurring cache by referenced merchants, not just FamilyMerchant

recurring_transactions.merchant_id can point at a shared ProviderMerchant
(recurring detection copies transaction.merchant_id), not just a
family-owned FamilyMerchant. merchants_version only tracked
Family#merchants (FamilyMerchant), so a ProviderMerchant update (e.g.
ProviderMerchant::Enhancer setting name/logo) left the cached projected
recurring list stale for up to a day.

Replace Family#merchants_version with #recurring_transaction_merchants_version,
scoped to the merchant records actually referenced by the family's recurring
transactions (both FamilyMerchant and ProviderMerchant), and bump the cache
key version. Also fix a flaky test assertion that matched all
recurring_transactions-table queries instead of the actual projection query,
since computing the cache key itself still runs small COUNT/MAX queries
against that table on a cache hit.

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com>
2026-08-25 03:40:57 +02:00
pro3958andagentloop fcb46be19f fix(transactions): re-render form when creating a transaction with no account (#2777)
TransactionsController#create looked up the account with
accessible_accounts.find(params.dig(:entry, :account_id)). With no
account selected the id is blank, find raises RecordNotFound, and
StoreLocation's rescue_from turns that into head :not_found — the 404
on /transactions the reporter saw.

Switch to find_by(id:) and, when it returns nil, rebuild the entry,
run validation, and re-render :new with 422, matching the existing
validation-failure branch. This covers a blank, missing, or invalid
account_id, so the user gets the form back with errors instead of a
dead button.

Fixes #2566

Co-authored-by: agentloop <agentloop@localhost>
2026-08-22 06:31:18 +02:00
9d225a21e6 fix: disable Mark as Recurring button when a manual recurring transaction already exists (#3103)
* fix: disable "Mark as Recurring" button when a manual recurring transaction already exists

Previously the button was always clickable and only failed after a POST,
showing "A manual recurring transaction already exists for this pattern".
Extract the lookup into Transaction#existing_manual_recurring_transaction
(reused by the controller guard) so the view can disable the button ahead
of time and show the reason inline.

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

* fix: address CodeRabbit review feedback on PR #3103

Move the existing_manual_recurring lookup out of the show view and into
the controller so rendering no longer runs an Active Record query
in-template, and strengthen the "no match" model test with near-match
recurring transactions that individually differ by account, merchant,
amount, currency, and manual flag.

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

* fix: move mark-recurring presentation state fully into controller, fix stale state on failed update

Address CodeRabbit follow-up on PR #3103:
- Compute the mark-recurring button's subtitle text/class, href, disabled
  state, title, and class entirely in TransactionsController (via a shared
  assign_mark_recurring_state helper) instead of deriving them with
  ternaries in the view.
- Populate that state before TransactionsController#update re-renders
  :show on a failed entry update, so the button doesn't incorrectly appear
  enabled when a matching manual recurring transaction exists.
- Add a controller test covering the failed-update render path.

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

* fix: use blank name instead of blank date to trigger validation failure in mark-recurring test

The CI test_unit run flagged a real bug in the test itself: TransactionsController#entry_params
strips blank :date/:amount before update, so date: "" never reached model validation and the
update succeeded (302) instead of failing (422) as the test expected. Use a blank :name instead,
which isn't stripped, and add DOM assertions (disabled button, no mark_as_recurring form action)
per CodeRabbit's follow-up review.

Verified against a live NAS Rails console reproduction (bypassing the test stack's broken
fixtures) that the failed-update render now correctly shows the button as disabled with the
"already exists" message and no action link.

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

* fix: use transaction id instead of entry id in mark-recurring route assertion

mark_as_recurring is a member route on the transactions resource keyed by the
Transaction's id, not the Entry's id (Entry uses delegated_type, so Entry and
its Transaction entryable have distinct ids). The prior assertion built the
path from `entry`, which could produce a different URL than the one actually
rendered, so the "no href" check could pass even if the button leaked a link.
Use entry.entryable so the assertion matches the real route.

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

* fix: refresh mark-recurring state on turbo_stream update, avoid unconditional query, keep DS::Button href

Addresses jjmata's review on PR #3103:
- Extract the "Mark as Recurring" block into a dom_id-wrapped partial and
  replace it in the successful update turbo_stream response, so inline
  edits that change whether the transaction matches an existing manual
  recurring transaction are reflected immediately instead of only on the
  next full page render.
- Skip the existing_manual_recurring_transaction lookup entirely when the
  block won't be rendered (no edit permission, or split-child entry),
  avoiding an unconditional extra query on every transaction show/failed
  update.
- Keep href present on the DS::Button and only toggle disabled, matching
  the established pattern elsewhere in the app, instead of nulling href
  (which flips the component to a bare <button> and leaks a stray
  method="post" attribute).

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

---------

Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-22 02:43:29 +02:00
fd01a5b3dc fix(accounts): remember transaction page size across account navigation (#3084)
* fix(accounts): remember transaction page size across account navigation

per_page was only ever read from the current request's query string, so
switching accounts always reset the activity feed back to 10 entries.
Reuses TransactionsController's existing prev_transaction_page_params
session store so the chosen page size applies consistently on both the
account detail page and the global transactions page.

Closes #3082

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

* fix(accounts): validate stored per_page and preserve it across filtered requests

Addresses review feedback on #3084: safe_per_page now validates the
stored default against the allowed values (a raw stored value like
"1" was previously passed through unchecked), TransactionsController
no longer wipes the remembered per_page when a request supplies
filters but omits per_page, and Session#prev_transaction_page_params
normalizes a NULL value to an empty hash.

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

* fix(transactions): use stored per_page as pagy fallback on filtered requests

store_params! already preserved the previously-selected per_page in the
session when a filtered request (e.g. dashboard money-flow links) omitted
it, but TransactionsController#index still called safe_per_page with its
hardcoded default of 10, so the stored preference was never applied to the
actual page rendered.

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

---------

Co-authored-by: Gerald <248542187+gfr-free@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-20 01:52:00 +02:00
GFRandClaude Sonnet 5 d0bb1a31e8 fix(recurring): include amount in manual recurring duplicate check (#2972)
* fix(recurring): include amount in manual recurring duplicate check

TransactionsController#mark_as_recurring blocked a second manual
recurring transaction whenever an existing one shared the same
account + payee name/merchant + currency, even when the amount
differed -- stricter than the DB unique indexes
(idx_recurring_txns_acct_name / idx_recurring_txns_acct_merchant),
RecurringTransaction::Identifier's own grouping key, and the
equivalent check already used in TransfersController#mark_as_recurring.

Add amount to the duplicate lookup so two distinct recurring payments
to the same payee at different amounts are both allowed, while an
exact duplicate is still blocked. Also rescue
ActiveRecord::RecordNotUnique around the create call so a race between
the pre-check and the DB constraint (e.g. a double-submit) surfaces
the same friendly "already exists" message instead of a generic
error, mirroring the existing race-handling pattern in
RecurringTransaction::Identifier.

Fixes #2936

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

* fix(recurring): don't blend distinct charge amounts into variance band

Once two manual recurring rows with the same payee/different amounts
can coexist (this PR), RecurringTransaction.create_from_transaction's
variance-band discovery still matched historical entries only by
account/payee/currency/day-window -- never by amount -- so it could
blend genuinely unrelated charges (e.g. a fee + a due from the same
merchant, same day) into one row's expected_amount_min/max/avg.
Flagged by Codex review on this PR.

Confirmed this is not hypothetical: two real production transactions
(3.00 and 19.68, same merchant, same day) got blended into a single
recurring row showing a fabricated "11.34" projected amount that
matches neither real transaction.

The same unfiltered matching independently exists in
RecurringTransaction::Identifier#manual_recurring_matches_entry?,
which periodically re-derives every manual recurring row's variance
after each sync (via IdentifyRecurringTransactionsJob). Both call
sites needed the fix together, or the job would silently re-blend
amounts on the next sync.

Add RecurringTransaction.amount_within_variance_band?(candidate,
anchor, ratio: 2) -- a candidate only counts as "the same fluctuating
payment" if it's within 2x (double/half) of the anchor. Anchored on
the target amount (not pairwise) so unrelated charges can't chain
together; ratio-based (not %-of-target-with-floor) so it's
scale-invariant and handles signed (expense) amounts correctly.
Threshold checked against real data: existing variance test fixtures
sit at ~1.2-1.3x (must stay included), the real corrupted case sits
at ~6.6x (must be excluded) -- 2x leaves comfortable margin on both
sides.

Wire this into find_matching_transaction_entries/
find_matching_transaction_amounts (SQL-level filter, same pattern as
the existing day-of-month bounds) and into
manual_recurring_matches_entry?. amount_window_scope/
matching_transactions and create_from_transfer need no changes --
confirmed by reading: the former only consumes an already-computed
band, the latter never does variance discovery at all.

Does not touch any already-corrupted production data -- deliberately
out of scope, discussed separately.

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

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-16 09:30:44 +02:00
William Wei MingandCursor af2ddca4ce Preload transfer counterparty associations on transactions index (#2819)
* fix(ci): skip scheduled preview cleanup on forks
Only run the hourly Cloudflare preview cleanup on we-promise/sure,
where the required secrets exist.

* Preload transfer counterparty associations on transactions index

Transfer#categorizable? walks inflow_transaction.entry.account during list
render, which N+1'd transactions, entries, and accounts per transfer row.

Co-authored-by: Cursor <cursoragent@cursor.com>

* Assert transfer rows render in transactions index N+1 test

* Broaden transactions index N+1 SQL matchers for lazy loads

* Drop unused outflow transfer preloads on transactions index

* Treat only equality SQL lookups as N+1 in index test

---------

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-04 23:21:11 +02:00
Jonathan ChangandJuan José Mata b9716a0485 fix: Transaction Pagination Skipping Entries (#2179)
* Fix transaction pagination regressions and CI blockers

* Rails EOL already fixed

---------

Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-06-16 10:51:51 +02:00
ghost a0f5e56668 perf(transactions): preload new form options (#2189)
* perf(transactions): preload new form options

* refactor(transactions): reuse new form account scope
2026-06-06 17:11:01 +02:00
Ang Wei Feng (Ted)andJuan José Mata 5e558fa3ab feat(transactions): add inline tag creation and search in txn form (#1719)
* feat(transactions): add inline tag creation and search in transaction forms

* fix(transactions): add tag-only update endpoint for edit drawer

* feat(transactions): implement TagSelectComponent for improved tag selection and management

* feat(tag-select): refactor tag selection component for improved functionality and accessibility

* feat(tag-select): implement inline tag rendering and error handling in tag selection component

* refactor(tag-select): remove unused list target from tag select controller

* fix: return forbidden JSON for denied tag updates

* fix: lock transaction tags when clearing them

* refactor: move tag select into DS namespace

* refactor: add multiselect trigger form field style

* fix: auto-position tag select dropdowns

* feat: add keyboard navigation to tag select

* feat: add create tag and search placeholder to transaction forms in multiple languages

* style: tighten tag select option spacing

* fix: align tag select spacing and focus behavior

* refactor: render tag badges with DS pill

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-06-01 21:46:32 +02:00
Xing HongandCopilot 475dbbfb8d fix: Enable and persist notes and tags on split child transactions (#1535) (#1552)
* fix: enable and persist notes on split child transactions (#1535)

* fix: enable tags on split child transactions and new tests for split child notes + tags

* Update app/components/DS/dialog_controller.js

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Xing Hong <39619359+xingxing21@users.noreply.github.com>

* fix(transactions): only stream notes frame when notes params are submitted

* fix(transactions): address PR review issues in notes stream and tests

---------

Signed-off-by: Xing Hong <39619359+xingxing21@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-04-29 18:17:36 +02:00
Yunwei Zhangandyunwei-zh 53ea0375db fix: values visible in privacy mode (#1473)
Co-authored-by: yunwei-zh <tspl.fin.guru@gmail.com>
2026-04-14 21:29:37 +02:00
Pedro J. AramburuandPedro J. Aramburu f699660479 Add exchange rate feature with multi-currency transactions and transfers support (#1099)
Co-authored-by: Pedro J. Aramburu <pedro@joakin.dev>
2026-04-08 21:05:58 +02:00
Juan Manuel ReyesandClaude Opus 4.6 f42b593b9e Show inflow/outflow totals for transfer filter (#1134)
* Show inflow/outflow totals when filtering by transfers

When filtering transactions by "Transfer" type, the summary bar previously
showed $0 for both Income and Expenses because transfers were excluded from
those sums. Now computes transfer inflow/outflow in the same SQL pass and
switches labels to "Inflow"/"Outflow" when transfer amounts are non-zero.

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

* Add mixed filter comment and transfer-only test coverage

Document the intentional mixed filter behavior where transfer amounts
are excluded from the summary bar when non-transfer types are present.
Add test exercising Inflow/Outflow label switching for transfer-only results.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 21:12:01 +01:00
soky srm f1991eaefe Recurring scoping implementation (#1300)
* Recurring scoping implementation

* FIX tests and reviews
2026-03-26 19:01:35 +01:00
soky srm 560c9fbff3 Family sharing (#1272)
* Initial account sharing changes

* Update schema.rb

* Update schema.rb

* Change sharing UI to modal

* UX fixes and sharing controls

* Scope include in finances better

* Update totals.rb

* Update totals.rb

* Scope reports to finance account scope

* Update impersonation_sessions_controller_test.rb

* Review fixes

* Update schema.rb

* Update show.html.erb

* FIX db validation

* Refine edit permissions

* Review items

* Review

* Review

* Add application level helper

* Critical review

* Address remaining review items

* Fix modals

* more scoping

* linter

* small UI fix

* Fix: Sync broadcasts push unscoped balance sheet to all users

* Update sync_complete_event.rb

 The fix removes the sidebar broadcasts (which rendered unscoped account groups using family.balance_sheet without user context)
  along with the now-unused sidebar_targets, account_group, and family_balance_sheet private methods.

  The sidebar will still update correctly — when the sync completes, Family::SyncCompleteEvent#broadcast fires family.broadcast_refresh, which triggers a
  morph-based page refresh for each user with their own authenticated session, rendering properly scoped sidebar content.
2026-03-25 10:50:23 +01:00
Renzo 581d3684b2 feat: Add duplicate button when a transaction is selected (#1123)
* feat: Add duplicate button when a transaction is selected

* feat: add merchant field

* feat: add duplicate transaction btn 2
2026-03-15 17:05:01 +01:00
LPWandluckyPipewrench 6197419f6c Add protection indicator to entries and unlock functionality (#765)
* feat: add protection indicator to entries and unlock functionality

- Introduced protection indicator component rendering on hover and in detail views.
- Added support to unlock entries, clearing protection flags (`user_modified`, `import_locked`, and locked attributes).
- Updated routes, controllers, and models to enable unlock functionality for trades and transactions.
- Refactored views and localized content to support the new feature.
- Added relevant tests for unlocking functionality and attribute handling.

* feat: improve sync protection and turbo stream updates for entries

- Added tests for turbo stream updates reflecting protection indicators.
- Ensured user-modified entries lock specific attributes to prevent overwrites.
- Updated controllers to mark entries as user-modified and reload for accurate rendering.
- Enhanced protection indicator rendering using turbo frames.
- Applied consistent lock state handling across trades and transactions.

* Address PR review comments for protection indicator

---------

Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
2026-01-24 16:03:23 +01:00
soky srmandJuan José Mata ebcd6360fd Add support for manual recurring transaction creation (#311)
* Support manual recurring

* Automatic variance calc

* Automatic variance update

* Tooltip for manual

* Review

* Fix variance calculations

Manual recurring updates collapse occurrence tracking when amounts repeat

* Proper Bigdecimal calcs

* Fix n+1 query

* Nicer UI errors.

* Style

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2025-11-14 00:31:12 +01:00
Zach Gollwitzer b7c56e2fb7 Test fixes 2025-07-23 20:00:32 -04:00
Zach Gollwitzer 1aae00f586 perf(transactions): add kind to Transaction model and remove expensive Transfer joins in aggregations (#2388)
* add kind to transaction model

* Basic transfer creator

* Fix method naming conflict

* Creator form pattern

* Remove stale methods

* Tweak migration

* Remove BaseQuery, write entire query in each class for clarity

* Query optimizations

* Remove unused exchange rate query lines

* Remove temporary cache-warming strategy

* Fix test

* Update transaction search

* Decouple transactions endpoint from IncomeStatement

* Clean up transactions controller

* Update cursor rules

* Cleanup comments, logic in search

* Fix totals logic on transactions view

* Fix pagination

* Optimize search totals query

* Default to last 30 days on transactions page if no filters

* Decouple transactions list from transfer details

* Revert transfer route

* Migration reset

* Bundle update

* Fix matching logic, tests

* Remove unused code
2025-06-20 13:31:58 -04:00
Zach Gollwitzer e657c40d19 Account:: namespace simplifications and cleanup (#2110)
* Flatten Holding model

* Flatten balance model

* Entries domain renames

* Fix valuations reference

* Fix trades stream

* Fix brakeman warnings

* Fix tests

* Replace existing entryable type references in DB
2025-04-14 11:40:34 -04:00
Josh Pigford 41873de11d Allow users to update their email address (#1745)
* Change email address

* Email confirmation

* Email change test

* Lint

* Schema reset

* Set test email sender

* Select specific user fixture

* Refactor/cleanup

* Remove unused email_confirmation_token

* Current user would never be true

* Fix translation test failures
2025-01-31 11:29:49 -06:00
Zach Gollwitzer c3248cd796 Improve account transaction, trade, and valuation editing and sync experience (#1506)
* Consolidate entry controller logic

* Transaction builder

* Update trades controller to use new params

* Load account charts in turbo frames, fix PG overflow

* Consolidate tests

* Tests passing

* Remove unused code

* Add client side trade form validations
2024-11-27 16:01:50 -05:00
Zach Gollwitzer cbba2ba675 Basic Plaid Integration (#1433)
* Basic plaid data model and linking

* Remove institutions, add plaid items

* Improve schema and Plaid provider

* Add webhook verification sketch

* Webhook verification

* Item accounts and balances sync setup

* Provide test encryption keys

* Fix test

* Only provide encryption keys in prod

* Try defining keys in test env

* Consolidate account sync logic

* Add back plaid account initialization

* Plaid transaction sync

* Sync UI overhaul for Plaid

* Add liability and investment syncing

* Handle investment webhooks and process current day holdings

* Remove logs

* Remove "all" period select for performance

* fix amount calc

* Remove todo comment

* Coming soon for investment historical data

* Document Plaid configuration

* Listen for holding updates
2024-11-15 13:49:37 -05:00
Zach Gollwitzer 4bfe47540d Basic trade and holdings view (#1271)
* Add trade view

* Lint fix

* Fix stale placeholder variable

* Add holding view
2024-10-09 14:59:18 -04:00
Zach Gollwitzer b200b71284 Add currency validation to account, update demo data generator (#996)
* Add currency validation to account, update demo data generator

* Fix tests
2024-07-17 14:18:12 -04:00
Zach Gollwitzer c6bdf49f10 Account::Sync model and test fixture simplifications (#968)
* Add sync model

* Fresh fixtures for sync tests

* Sync tests overhaul

* Fix entry tests

* Complete remaining model test updates

* Update system tests

* Update demo data task

* Add system tests back to PR checks

* More simplifications, add empty family to fixtures for easier testing
2024-07-10 11:22:59 -04:00
Zach Gollwitzer c3314e62d1 Account::Entry Delegated Type (namespace updates part 7) (#923)
* Initial entryable models

* Update transfer and tests

* Update transaction controllers and tests

* Update sync process to use new entries model

* Get dashboard working again

* Update transfers, imports, and accounts to use Account::Entry

* Update system tests

* Consolidate transaction management into entries controller

* Add permitted partial key helper

* Move account transactions list to entries controller

* Delegate transaction entries search

* Move transfer relation to entry

* Update bulk transaction management flows to use entries

* Remove test code

* Test fix attempt

* Update demo data script

* Consolidate remaining transaction partials to entries

* Consolidate valuations controller to entries controller

* Lint fix

* Remove unused files, additional cleanup

* Add back valuation creation

* Make migrations fully reversible

* Stale routes cleanup

* Migrations reversible fix

* Move types to entryable concern

* Fix search when no entries found

* Remove more unused code
2024-07-01 10:49:43 -04:00
Zach Gollwitzer da18c3d850 Account namespace updates: part 6 (transactions) (#904)
* Move Transaction to Account namespace

* Fix improper routes, improve separation of concerns

* Replace account transactions list partial with view

* Remove logs

* Consolidate transaction views

* Remove unused code

* Transfer style tweaks

* Remove more unused code

* Add back totals by currency helper
2024-06-24 11:58:39 -04:00
Zach Gollwitzer 12380dc8ad Account namespace updates: part 5 (valuations) (#901)
* Move Valuation to Account namespace

* Move account history to controller

* Clean up valuation controller and views

* Translations and cleanup

* Remove unused scopes and methods

* Pass brakeman
2024-06-21 16:23:28 -04:00
Karan Kiridependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>Zach GollwitzerMattiaZach GollwitzerJakub Kottnauerziraq young
e13c3d9271 feat: Transaction pagination Improvements (#873)
* feat: make transaction container fixed height

* feat: pagination per page query

* fix: linting errors

* Changelog page that pulls from Github Release notes (#867)

* Changelog page that pulls from Github Release notes

* Review changelog page styles

* Move changelog page title to i18n translations

* Bump to 0.1.0-alpha.6

Signed-off-by: Zach Gollwitzer <zach@maybe.co>

* Bump aws-sdk-s3 from 1.152.0 to 1.152.3 (#880)

Bumps [aws-sdk-s3](https://github.com/aws/aws-sdk-ruby) from 1.152.0 to 1.152.3.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-s3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump mocha from 2.3.0 to 2.4.0 (#878)

Bumps [mocha](https://github.com/freerange/mocha) from 2.3.0 to 2.4.0.
- [Changelog](https://github.com/freerange/mocha/blob/main/RELEASE.md)
- [Commits](https://github.com/freerange/mocha/compare/v2.3.0...v2.4.0)

---
updated-dependencies:
- dependency-name: mocha
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump octokit from 8.1.0 to 9.1.0 (#877)

Bumps [octokit](https://github.com/octokit/octokit.rb) from 8.1.0 to 9.1.0.
- [Release notes](https://github.com/octokit/octokit.rb/releases)
- [Changelog](https://github.com/octokit/octokit.rb/blob/main/RELEASE.md)
- [Commits](https://github.com/octokit/octokit.rb/compare/v8.1.0...v9.1.0)

---
updated-dependencies:
- dependency-name: octokit
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump rails from `f9c847f` to `5d34172` (#879)

Bumps [rails](https://github.com/rails/rails) from `f9c847f` to `5d34172`.
- [Release notes](https://github.com/rails/rails/releases)
- [Commits](https://github.com/rails/rails/compare/f9c847fac102039d9174106f44b59144da267751...5d34172ff44ec0c88ac03a979679b31e1ed78745)

---
updated-dependencies:
- dependency-name: rails
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Zach Gollwitzer <zach@maybe.co>

* Update issue templates

* Add merchant select when editing transaction (#885)

* Transaction transfers, payments, and matching (#883)

* Add transfer model and clean up family snapshot fixtures

* Ignore transfers in income and expense snapshots

* Add transfer validations

* Implement basic transfer matching UI

* Fix merge conflicts

* Add missing translations

* Tweak selection states for transfer types

* Add missing i18n translation

* Ensure correct form's hidden input for selectedIds (#891)

* feat: make transaction container fixed height

* feat: pagination per page query

* fix: linting errors

* Transaction transfers, payments, and matching (#883)

* Add transfer model and clean up family snapshot fixtures

* Ignore transfers in income and expense snapshots

* Add transfer validations

* Implement basic transfer matching UI

* Fix merge conflicts

* Add missing translations

* Tweak selection states for transfer types

* Add missing i18n translation

* feat: make transaction container fixed height

* feat: pagination per page query

* fix: linting errors

* revert unnecessary changes

* revert unnecessary changes

* code review changes

* code review changes

* code review changes

* remove unused imports

* fix: unit tests

* remove border

* fix: transaction padding

* fix: transaction container height

---------

Signed-off-by: Zach Gollwitzer <zach@maybe.co>
Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Karan Kiri <karankiri.96@gmail.com>
Co-authored-by: Mattia <malnis.mattia@gmail.com>
Co-authored-by: Zach Gollwitzer <zach@maybe.co>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Zach Gollwitzer <zach.gollwitzer@gmail.com>
Co-authored-by: Jakub Kottnauer <jk@jakubkottnauer.com>
Co-authored-by: ziraq young <ziraqyoung@outlook.com>
2024-06-21 12:04:40 -04:00
Zach Gollwitzer dc3147c101 Move merchants to top-level namespace (#895) 2024-06-20 08:38:59 -04:00
Zach Gollwitzer 2681dd96b1 Move categories to top-level namespace (#894) 2024-06-20 08:15:09 -04:00
Zach Gollwitzer ca39b26070 Transaction transfers, payments, and matching (#883)
* Add transfer model and clean up family snapshot fixtures

* Ignore transfers in income and expense snapshots

* Add transfer validations

* Implement basic transfer matching UI

* Fix merge conflicts

* Add missing translations

* Tweak selection states for transfer types

* Add missing i18n translation
2024-06-19 06:52:08 -04:00
Zach Gollwitzer a681e73fea Enable bulk editing of transactions (#846) 2024-06-07 18:59:46 -04:00
Zach Gollwitzer d3f9be15f1 Bulk transaction deletion (#845)
* Clean up transaction show view, add delete button

* Clean up tailwind global styles, add switch

* Bulk deletion controller and tests

* Normalize translations

* Add bulk deletion button and form
2024-06-07 16:56:30 -04:00
Zach Gollwitzer 4ebc08e5a4 Transactions cleanup (#817)
An overhaul and cleanup of the transactions feature including:

- Simplification of transactions search and filtering
- Consolidation of account sync logic after transaction change
- Split sidebar modal and modal into "drawer" and "modal" concepts
- Refactor of transaction partials and folder organization
- Cleanup turbo frames and streams for transaction updates, including new Transactions::RowsController for inline updates
- Refactored and added several integration and systems tests
2024-05-30 20:55:18 -04:00
Jakub Kottnauer ad4de99f1a Add partial account sync support (#653)
* Add partial account sync support

* Fix indentation

* Use historical balance as base when doing partial sync

* Simplify controller crud tests

* Fix linter errors
2024-04-24 15:55:52 -04:00
Jose Farias cd8d741fe1 Add transaction modal flow (#633)
* Add transaction modal flow

* Preserve decimals when creating transactions
2024-04-16 14:44:31 -04:00
Zach Gollwitzer fe2fa0eac1 Multi-currency support: Money + Currency class improvements (#553)
* Money improvements

* Replace all old money usage
2024-03-18 11:21:00 -04:00
Zach Gollwitzer 7d48c01833 Prepare fixture data for account sync tests (#493)
* Rename account balance field for clarity

`original_balance` and `original_currency` may infer that these values are "original" to the account.  In reality, they represent the "current" balance and currency on the account.

* Prepare fixture data for account sync testing

* Update to new field

* Fix conflicts

* Remove local schema change
2024-02-27 12:43:49 -05:00
Dwight Watson 971347c761 Find account first and build transaction through association (#487)
* Find account first and build transaction through association

* Fix flaky test
2024-02-26 06:29:28 -05:00
Zach Gollwitzer 87b97b3c41 Scaffold out basic transactions model and UI (#478)
* Transaction scaffold

* Rough in transaction views

* Fix sort order

* Fix mass assignment issue

* Fix test

* Simplify CI workflow

* Don't seed db before test
2024-02-23 21:34:33 -05:00