Commit Graph

1447 Commits

Author SHA1 Message Date
soky srm
97eacc515c Investments currency fix (#1436)
* Investments currency fix

* FIX Money multiplication
2026-04-11 15:09:59 +02:00
Tao Chen
8f5694dd79 add icon for Transfer (#1431) 2026-04-11 09:37:27 +02:00
Roger Saner
88747e5716 feat(transaction): tabbing between income and expenses persists entered data (#1422) 2026-04-11 00:56:05 +02:00
Juan José Mata
257286431b Fix trade drawer header width regression (#1415)
* Fix trade drawer header width regression

Wrap the trade header partial in a grow/min-w-0 container inside the custom dialog header row so overview disclosure rows stretch to available width instead of shrinking to content.

Confirmed via git blame that this layout behavior predates PR #1248 and is tied to the custom header flex layout introduced in commit 7ae9077.

* Overlay trade drawer close button to preserve content width

Render the close button absolutely in the custom header instead of as a flex sibling of the full trades header partial. This prevents the button column from shrinking the overview section width and leaving a persistent right-side gutter.
2026-04-11 00:51:29 +02:00
Louis
e96fb0c23f feat(enable-banking): enhance transaction import, metadata handling, and UI (#1406)
* feat(enable-banking): enhance transaction import, metadata handling, and UI

* fix(enable-banking): address security, sync edge cases and PR feedback

* fix(enable-banking): resolve silent failures, auth overrides, and sync logic bugs

* fix(enable-banking): resolve sync logic bugs, trailing whitespaces, and apply safe_psu_headers

* test(enable-banking): mock set_current_balance to return success result

* fix(budget): properly filter pending transactions and classify synced loan payments

* style: fix trailing whitespace detected by rubocop

* refactor: address code review feedback for Enable Banking sync and reporting

---------

Signed-off-by: Louis <contact@boul2gom.com>
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-10 23:19:48 +02:00
Ang Wei Feng (Ted)
d6d7df12fd fix(accounts): add duplicate action to activity view (#1418) 2026-04-10 23:06:32 +02:00
Juan José Mata
65c5f8eb07 Fix DemoFamilyRefreshJob demo email config lookup (#1426)
* Fix demo refresh email config lookup

Use indifferent access when reading demo config so the refresh job works whether config keys are strings or symbols. Add a regression test covering symbol-keyed config_for output.

* Remove unnecessary blank line in test file

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-10 17:42:51 +02:00
soky srm
dcebda05de Move back to brandfetch (#1427)
* Move back to brandfetch

* Update security.rb

* Update security.rb
2026-04-10 17:42:16 +02:00
soky srm
0aca297e9c Add binance security provider for crypto (#1424)
* Binance as securities provider

* Disable twelve data crypto results

* Add logo support and new currency pairs

* FIX importer fallback

* Add price clamping and optiimize retrieval

* Review

* Update adding-a-securities-provider.md

* day gap miss fix

* New fixes

* Brandfetch doesn't support crypto. add new CDN

* Update _investment_performance.html.erb
2026-04-10 15:43:22 +02:00
Louis
6551aaee0f fix(binance): fix hmac signature by using same parameter order in request and sign (#1425) 2026-04-10 15:40:13 +02:00
soky srm
7908f7d8a4 Expand financial providers (#1407)
* Initial implementation

* Tiingo fixes

* Adds 2 providers, remove 2

* Add  extra checks

* FIX a big hotwire race condition

// Fix hotwire_combobox race condition: when typing quickly, a slow response for
// an early query (e.g. "A") can overwrite the correct results for the final query
// (e.g. "AAPL"). We abort the previous in-flight request whenever a new one fires,
// so stale Turbo Stream responses never reach the DOM.

* pipelock

* Update price_test.rb

* Reviews

* i8n

* fixes

* fixes

* Update tiingo.rb

* fixes

* Improvements

* Big revamp

* optimisations

* Update 20260408151837_add_offline_reason_to_securities.rb

* Add missing tests, fixes

* small rank tests

* FIX tests

* Update show.html.erb

* Update resolver.rb

* Update usd_converter.rb

* Update holdings_controller.rb

* Update holdings_controller.rb

* Update holdings_controller.rb

* Update holdings_controller.rb

* Update holdings_controller.rb

* Update _yahoo_finance_settings.html.erb
2026-04-09 18:33:59 +02:00
Juan José Mata
a30e9b75a7 Fix Binance USD converter custom rate keyword (#1414) 2026-04-08 22:23:15 +02:00
Pedro 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
soky srm
1d7c4158d4 Merge pull request #925 from grrtt49/feature/future-budget
feat: Allow creating budgets up to 2 years ahead
2026-04-08 08:35:47 +02:00
Derek Brown
133582ef4d Fix balance sheet dashboard section on iPhone (#1318)
* Update _balance_sheet.html.erb

Update Balance Sheet to work on iPhone Pro Max without scrolling

Signed-off-by: Derek Brown <browndw4@gmail.com>

* Update _group_weight.html.erb

Make the % icon smaller (5 bars not 10) to fit better on smaller format devices

Signed-off-by: Derek Brown <browndw4@gmail.com>

* Update _group_weight.html.erb

Resolve Codex comment

Signed-off-by: Derek Brown <browndw4@gmail.com>

* Update _balance_sheet.html.erb

Increasing width of the weight column

Signed-off-by: Derek Brown <browndw4@gmail.com>

---------

Signed-off-by: Derek Brown <browndw4@gmail.com>
2026-04-07 20:53:04 +02:00
Tao Chen
2658c36b05 feat(select): improve merchant dropdown behavior and placement controls (#1364)
* feat(select): improve merchant dropdown behavior and placement controls

 - add configurable menu_placement strategy to DS::Select (auto/down/up) with safe normalization
forward menu_placement through StyledFormBuilder#collection_select
 - force Merchant dropdown to open downward in transaction create and editor forms
 - fix select option/search text contrast by applying text-primary in DS select menu
 - prevent form jump on open by scrolling only inside dropdown content instead of using scrollIntoView
 - clamp internal dropdown scroll to valid bounds for stability
- refactor select controller placement logic for readability (placementMode, clamp) without changing behavior

* set menu_placement=auto for metchant selector
2026-04-07 20:52:14 +02:00
soky srm
be42988adf Add throttling and cross-rate for twelve data (#1396)
* Add throttling and cross-rate for twelve data

* FIX yahoo precision also

* FIXES

* Update importer.rb

* Fixes

* Revert job

* Fixes
2026-04-07 20:46:05 +02:00
Copilot
ec1562782b Make parent budgets auto-aggregate from subcategory edits (#1312)
* Initial plan

* Auto-sum parent budgets from subcategory edits

Agent-Logs-Url: https://github.com/we-promise/sure/sessions/f1c1b9ef-0e5d-4300-8f1b-e40876abfdcd

Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>

* Finalize subcategory budget parent aggregation

Agent-Logs-Url: https://github.com/we-promise/sure/sessions/f1c1b9ef-0e5d-4300-8f1b-e40876abfdcd

Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>

* Address follow-up review on budget aggregation

Agent-Logs-Url: https://github.com/we-promise/sure/sessions/b773decd-69a2-4da9-81ed-3be7d24cbb52

Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jjmata <187772+jjmata@users.noreply.github.com>
2026-04-07 16:41:45 +02:00
Louis
d3469a91f2 Refactor: Use Encryptable concern in CoinbaseItem (#1339)
Remove the duplicated encryption_ready? method in favor of the Encryptable concern which provides the exact same functionality.
2026-04-07 16:28:01 +02:00
sentry[bot]
117ab2b45f refactor(accounts): Improve destroy_later atomicity and add controller error handling (#1395)
* refactor(accounts): Improve destroy_later atomicity and add controller error handling

* Address PR comment

---------

Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-07 15:53:25 +02:00
Louis
455c74dcfa Add Binance support, heavily inspired by the Coinbase one (#1317)
* feat: add Binance support (Items, Accounts, Importers, Processor, and Sync)

* refactor: deduplicate 'stablecoins' constant and push stale_rate filter to SQL

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-07 14:43:17 +02:00
Mikael Møller
5cb474d61c Quick Categorize Wizard — follow-up fixes (#1393)
* Extract Entry.uncategorized_transactions scope, remove Family#uncategorized_transaction_count

Adds a single Entry.uncategorized_transactions scope containing the
shared conditions (transactions join, active accounts, category nil,
not transfer kinds, not excluded). All callers now use this scope:

- Entry.uncategorized_matching builds on it
- Transaction::Grouper::ByMerchantOrName#uncategorized_entries uses it
- categorizes_controller#uncategorized_entries_for uses it (also fixes
  missing status/excluded filters that were silently absent before)
- Both controllers replace Current.family.uncategorized_transaction_count
  with Current.accessible_entries.uncategorized_transactions.count so
  the button count and wizard count both respect account sharing

Family#uncategorized_transaction_count removed as it is now unused and
was family-scoped rather than user-scoped.

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

* Scope assign_entry write to Current.accessible_entries

Replaces unscoped Entry.where(id:) with Current.accessible_entries.where(id:)
so the write path is consistent with the find above it. Not exploitable
given the find would 404 first, but removes the pattern inconsistency.

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

* Add privacy-sensitive class to amounts in categorize wizard

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

* Extract uncategorized_count helper in CategorizesController

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

* Fix comment on uncategorized_transactions scope to mention draft accounts

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

* Use uncategorized_count helper in assign_entry action

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-07 13:17:37 +02:00
Louis
cc8d6ca2a0 fix: allow high precision for security prices in trade forms (to solve #1323) (#1342)
* fix: allow high precision for security prices in trade forms (to solve #1323)

* fix: prevent race conditions on currency selection in money field

* fix: silently ignore currency fetch errors in money field
2026-04-07 12:19:17 +02:00
UberDudePL
cebdf1d4f7 Polish localization: complete translations, pluralization fixes, and reusable locale audit tooling (#1356)
* Add production-ready Polish localization and reusable locale audit tooling

- add and update Polish locale files across models, views, mailers, and shared translations
- add runtime rails-i18n dependency and Polish locale support in language helper
- add regression coverage for Polish pluralization and locale-aware money formatting
- introduce reusable locale audit script for any locale plus backward-compatible PL wrapper
- add localization audit docs and generated PL readiness/pluralization reports
- resolve one/few/many/other pluralization consistency for Polish locales

* Fix Polish locale review feedback

* Fix locale compatibility regressions

* Polish locale typo pass and wrapper cleanup

* Final language improvements and test isolation for Polish locales

- Improved partial_success wording in SnapTrade with proper noun inflection
- Fixed typos: Pomin → Pomiń in Mercury and LunchFlow items
- Isolated I18n backend state in polish_pluralization_test to prevent test coupling

* Fix code review comments in locale audit scripts

- Use RbConfig.ruby instead of 'ruby' to ensure consistent interpreter
- Remove Symbol from permitted_classes and explicitly allow CLDR plural symbols (one, few, many, other) in YAML loading

* Simplify i18n flow and align locale interpolation keys

* Remove locale audit scripts and localization docs
2026-04-07 11:55:58 +02:00
Geoffrey
ac2817d704 Fixed crypto and loan add menus (#1306)
* Fixed crypto and loan add menus

* Changed unspecified crypto account type to none for consistency

* Added default add message for loan subtype

* Made the short form of non-mortgage loans in loans.rb match the long form

* Edited the crypto tooltip to be country generic

* Update config/locales/views/loans/en.yml

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Geoffrey <79559478+CYBRXT@users.noreply.github.com>

* Update app/views/loans/_form.html.erb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Geoffrey <79559478+CYBRXT@users.noreply.github.com>

* Following Dosu's comment on my issue for consistency

---------

Signed-off-by: Geoffrey <79559478+CYBRXT@users.noreply.github.com>
Co-authored-by: Geoffrey <geoffrey@github.worker>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-04-07 11:39:18 +02:00
Mikael Møller
0870ebb56b Add Quick Categorize Wizard (#1386)
* Add Quick Categorize Wizard (iteration 1)

Adds a step-by-step wizard for bulk-categorizing uncategorized transactions
and optionally creating auto-categorization rules, reducing friction after
connecting a new bank account.

New files:
- Transaction::Grouper abstraction + ByMerchantOrName strategy (groups by
  merchant name when present, falls back to entry name; sorted by count desc)
- Transactions::CategorizesController (GET show / POST create)
- Wizard view at app/views/transactions/categorizes/show.html.erb
- Stimulus categorize_controller.js (Enter-key-to-select-first)
- Tests for grouper and controller

Modified files:
- routes.rb: resource :categorize inside namespace :transactions
- transactions_controller.rb: expose @uncategorized_count to index
- transactions/index.html.erb: Categorize (N) button in header
- family.rb: uncategorized_transaction_count query
- rules_controller.rb: return_to param support for wizard → rule editor flow
- rules/_form.html.erb, rules/new.html.erb: pass return_to through form
- i18n: categorizes show/create keys + rules.create.success

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

* Quick Categorize Wizard — iteration 2 polish

Six improvements from live testing:

- Breadcrumb: Home > Transactions > Categorize
- Layout: category picker + confirmation dialog above transaction list
- Inline confirmation dialog: clicking a category pill shows a <dialog>
  summarising what will happen (N transactions → category, rule if checked)
  with Confirm and Cancel buttons — no redirect to rule editor
- Direct rule creation: rule created with active: true in the controller
  instead of redirecting to the rule editor; revert return_to plumbing from
  RulesController, rules/_form, rules/new, rules/en.yml
- Individual row assignment: per-row category <select> submits via
  PATCH /transactions/categorize/assign_entry and removes the row via
  Turbo Stream (assign_entry action + route)
- Enter key guard: selectFirst only fires when exactly 1 pill is visible
  after filtering

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

* Quick Categorize Wizard — iteration 3 reliability fixes and UX polish

- Fix Stimulus controller not loading: remove invalid `@hotwired/turbo` named
  import (not in importmap); use global `Turbo.renderStreamMessage` instead
- Fix Enter key submitting form with wrong category when search field is
  unfocused: move keydown listener to document so it fires regardless of focus
- Prevent Enter from submitting when multiple categories are visible
- Clear search filter after bulk category assignment (pill click or Enter),
  but not after individual row dropdown assignment
- Update group transaction count and total amount live as entries are assigned
  via row dropdown or partial bulk assignment
- Add turbo frames for remaining count and group summary so they update
  without a full page reload

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

* Quick categorization polish

* refactoring

* Remove unused GROUPS_PER_BATCH constant, fix ERB self-closing tags

Wizard only ever uses one group at a time so limit: 1 is correct and
more honest than fetching 20 and discarding 19. ERB linter fixes are
whitespace/void-element corrections with no functional change.

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

* Move Categorize button into ... menu on transactions index

Reduces header clutter by putting it in the overflow menu at the bottom,
where it only appears when there are uncategorized transactions.

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

* Scope categorize wizard to accessible entries only

Fixes a security issue where users with restricted account access via
account sharing could view and categorize transactions from accounts
they cannot access through normal transaction flows.

- Pass Current.accessible_entries to Transaction::Grouper so the wizard
  only displays groups from accounts the user can see
- Use Current.accessible_entries on all write paths in create and
  assign_entry, matching the pattern in TransactionCategoriesController
- Refactor Grouper to accept an entries scope instead of a family object,
  keeping authorization concerns in the controller
- Add tests verifying inaccessible entries are hidden from the wizard
  and cannot be categorized via forged POST/PATCH params

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

* Clamp position param to >= 0 to guard against negative offset

Prevents ArgumentError from Array#drop when a negative position is
passed via a tampered query string or form value.

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

* Surface rule creation failure and add accessible names to entry row

- Capture Rule.create_from_grouping! return value; set flash[:alert] when
  nil so users who checked "Create Rule" know it wasn't created (e.g. a
  duplicate already exists); stream the notification for partial updates
- Add aria-label to the per-row checkbox and category select in
  _entry_row so screen readers can identify which transaction each
  control belongs to

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

* Localize breadcrumb labels in categorizes controller

Follows the pattern used by FamilyExportsController and ImportsController.
Adds 'transactions' and 'categorize' keys to the breadcrumbs locale file.

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

* Add error handling to categorize controller fetch calls

Check response.ok before parsing the body and add .catch handlers
so network failures and non-2xx responses are logged rather than
silently swallowed. On assignment failure the per-row select is
reset to empty so the user can retry.

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

* Scope preview_rule to accessible entries only

Entry.uncategorized_matching now accepts an entries scope instead of a
family object, matching the same pattern used for Transaction::Grouper.
The preview_rule action passes Current.accessible_entries so rule
previews respect account sharing permissions.

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

* Scope remaining count to accessible entries

Adds Entry.uncategorized_count(entries) following the same pattern as
uncategorized_matching. Replaces all three uses of
Current.family.uncategorized_transaction_count in the categorize
controller so the remaining-count badge reflects only the transactions
the current user can actually access and categorize.

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

* Comments got separated from their function

* Remove quick-categorize-wizard dev notes

This was a planning document used during development, not intended
for the final branch.

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

* Recompute remaining entries from server state after writes

Adds uncategorized_entries_for helper that reloads remaining entries
from the DB with a category_id IS NULL filter after each write, so
the partial-update Turbo Stream reflects server-side state rather than
trusting the client-provided remaining_ids. This handles the case where
a concurrent request has categorized one of the remaining entries
between page render and form submit.

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

* Rename create_from_grouping! to create_from_grouping

The method rescues RecordInvalid and returns nil, which contradicts
the bang convention. Dropping the ! correctly signals that callers
should check the return value.

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

* Clamp offset in grouper to guard against negative values

The controller already clamps position before passing it as offset,
but clamping in the grouper itself prevents ArgumentError from
Array#drop if the grouper is ever called directly with a negative offset.

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-04-07 11:24:50 +02:00
Neeraj Verma
df2863ea7b added collect_health_stats to enablebanking syncer (#1390)
Also made improvements to linked_accounts query
2026-04-07 10:43:57 +02:00
Neeraj Verma
246cd00cbb collect transaction stats after sync in EnableBanking provider (#1388)
* collect transaction stats after sync in EnableBanking provider

* update logic to follow the pattern used by other bank providers

* fix n+1 issue

* fix N+1 issues
2026-04-06 13:49:46 +02:00
Serge L
78b334277c QIF imports: Add date format auto-detection and manual override (#1368)
* feat: improve QIF import date format selection

- Added a reusable date format auto-detection method.

- Show a live preview of the first parsed date that updates client-side
  as the user changes the dropdown selection, via a new
  qif-date-format Stimulus controller.

- Show an error alert and disable the submit button when no supported
  date format can parse the file's dates.

* A few polishing fixes:
- Missing return on redirects
Stale REASONABLE_DATE_RANGE constant.
- Replaced the frozen constant with a class method
Bare inline rescue — Replaced Date.strptime(s, fmt) rescue nil with an explicit begin/rescue catching.
- save!(validate: false) in controller — Changed to update_column(:column_mappings, ...) in qif_category_selections_controller.rb:22, matching the pattern used in detect_and_set_qif_date_format!.
- Unescaped JSON in HTML attribute — Replaced the raw <div> with tag.div ... do block in show.html.erb:16, letting Rails properly escape the data attribute value.

* fix: address review feedback for QIF date format feature

- Add missing `return` after redirect for non-QIF imports
- Pass date_format to parse_opening_balance in will_adjust_opening_anchor?
- Return empty array when no usable date sample exists for format preview
- Add sr-only label to date format select for accessibility
- Consolidate duplicate try_parse_date/parse_qif_date into single method
- Remove misleading ambiguity scoring comment from detect_date_format
- Skip redundant sync_mappings when date format already triggered a sync

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

* Use %{product_name} interpolation in locale strings

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-05 09:27:24 +02:00
sentry[bot]
a76aa340d5 fix: prevent NoMethodError in foreign_account? when account family is nil (#1376)
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
2026-04-05 09:25:18 +02:00
Mike Lloyd
281197f918 Fix opacity for excluded transactions and implement keyboard navigation (#1332)
* Make category selection menus opaque for excluded transactions

* Allow keyboard navigation in category selection menu

* Fix category transparency on mobile

* Make checkbox opaque

* Remove text-secondary from amount container

* Submit form directly

* Handle aria labels
2026-04-04 13:29:43 +02:00
Brian Richard
94e7f7f0a0 fix: enhance text contrast for headings, and paragraphs in blockquotes in dark mode on the Guide page (#1369) 2026-04-04 02:30:17 +02:00
Kenrick Tandrian
c26bf484fb fix(ui): move repeat icon to the center (#1365) 2026-04-04 02:27:23 +02:00
Tomer Horowitz
0dd3990502 fix: preserve wrapped rule import json values (#1358) 2026-04-03 12:38:37 +02:00
Yunwei Zhang
6d7ae0aa8a Fix: target="_blank" to contact button (#1359)
Co-authored-by: yunwei-zh <tspl.fin.guru@gmail.com>
2026-04-03 12:36:35 +02:00
Tomer Horowitz
d6183be1ae fix: instantiate RuleImport before generating rows (#1354)
* fix: instantiate RuleImport before generating rows

* test: use API keys in imports controller tests
2026-04-03 01:33:11 +02:00
Derek Brown
9a1cd1130a Update _form.html.erb (#1343)
@dosubots suggested fix

Signed-off-by: Derek Brown <browndw4@gmail.com>
2026-04-02 20:16:21 +02:00
Louis
8ed69132cf fix: add hex color validation to Category model and form (to solve #1247) (#1341)
- Added server-side validation to Category model to enforce 6-digit hex format for colors.
- Added HTML pattern attribute to category form for client-side validation.
- Updated tests to cover validation and fixed existing tests using shorthand hex colors.
2026-04-01 20:27:29 +02:00
Anas Limouri
a90f9b7317 Add CoinStats exchange portfolio sync and normalize linked investment charts (#1308)
* [FEATURE] Add CoinStats exchange portfolios and normalize linked investment charts

* [BUGFIX] Fix CoinStats PR regressions

* [BUGFIX] Fix CoinStats PR review findings

* [BUGFIX] Address follow-up CoinStats PR feedback

* [REFACTO] Extract CoinStats exchange account helpers

* [BUGFIX] Batch linked CoinStats chart normalization

* [BUGFIX] Fix CoinStats processor lint

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-04-01 20:25:06 +02:00
sentry[bot]
f63630c0fa Fix NoMethodError on nil accountable for logo color (#1334)
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
2026-04-01 20:19:56 +02:00
Juan José Mata
43d617661f Missing translation fallback for account subtypes (#1325)
* Fix missing translation fallback for account subtypes in LunchFlow and Mercury

The translate_subtypes lambda called t() without a default: fallback, causing
"Translation missing" for the ~39 investment subtypes not in the locale files.
Now falls back to the :long label from the model's SUBTYPES hash (e.g. "457(b)",
"SEP IRA", "UGMA Custodial Account"), matching the pattern used by Accountable#subtype_label_for.

https://claude.ai/code/session_01HBJzNkvpky8mKrLkzv83Mm

* Default to single-column dashboard

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-31 17:22:49 +02:00
Juan José Mata
8970211476 LunchFlow referral codes 2026-03-31 15:27:38 +02:00
Serge L
861a2d2d91 Fix NoMethodError on nil entryable in account activity feed (#1316)
* Fix NoMethodError when entry has nil entryable

Guard against orphaned entries where the entryable record has been
deleted but the entry still exists, preventing a crash on the
account show page.

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

* Add dependent: :destroy to Entryable has_one :entry

The polymorphic has_one :entry association lacked a dependent option,
meaning if a Transaction/Trade/Valuation was ever deleted directly
(bypassing the Entry), the Entry would be left orphaned with a nil
entryable — causing NoMethodError in the activity feed.

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

* Add nil entryable guard to _split_group.html.erb

Same defensive check as _entry.html.erb for consistency.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 17:30:12 +02:00
soky srm
c14ba6d0c9 FIX (#1315)
- split transaction mobile input
- privacy for day totals
2026-03-29 17:28:07 +02:00
Serge L
ab9b97639b Record dividends and interest as Trades in investment accounts (#1311)
* Record dividends and interest as Trades in investment accounts

All investment income (dividends and interest) is now modeled as a
Trade with qty: 0 and price: 0, keeping security_id NOT NULL on trades
intact. Dividends require a security; interest falls back to a
per-account synthetic cash security (kind: "cash", offline: true) when
none is selected, matching how brokerages handle uninvested cash
internally.

- Add `kind` column to securities ("standard" | "cash") with DB check
  constraint; `Security.cash_for(account)` lazily finds or creates the
  synthetic cash security; `scope :standard` excludes synthetic
  securities from user-facing pickers
- Trade::CreateForm: new `dividend` type (security required); `interest`
  now creates a Trade instead of a Transaction
- Trade form: Dividend and Interest in the type dropdown with a security
  combobox (required for dividend, optional for interest)
- transactions table: untouched

* UI fixes

* HealthChecker — both scopes now chain .standard to exclude cash securities from provider health checks.

DB query moved to model — Account#traded_standard_securities in app/models/account.rb, view uses account.traded_standard_securities.

DRY income creation — create_income_trade(sec:, label:, name:) extracted as shared private method; create_dividend_income and create_interest_income delegate to it.

show.html.erb blocks merged — single unless trade.qty.zero? block covers qty/price/fee fields.

Test extended — assert_response :unprocessable_entity added after the assert_no_difference block.

* Hide cash account ticker from no-security trade detail

* Fix CodeRabbit review issues from PR #1311

- Remove duplicate YAML keys in translation files (de, es, fr)
- Add error handling for security resolution in create_dividend_income
- Extract income trade check to reduce duplication in header template

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* Include holdings in dividend/interest security picker

The security picker for dividend/interest trades should include all securities
in holdings, not just those with trade history. This fixes the issue where
accounts with imported holdings (e.g., SimpleFIN) but no trades would have an
empty picker and be unable to record dividends.

Uses UNION to combine securities from both trades and holdings.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>

* scope picker to holdings only (a trade creates a holding anyway)

---------

Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
2026-03-29 10:08:54 +02:00
Serge L
cc7d675500 Add transaction fee support to trades (#1248)
Add an optional fee field (decimal, precision: 19, scale: 4) to trades.
Fee is included in the total amount calculation (qty * price + fee) for
both create and update flows. The fee field appears on both the create
and edit forms, defaults to 0, and auto-submits like other trade fields.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 19:03:16 +01:00
0xRozier
005d2fac20 Fix/issue 954 enable banking duplicate transactions (#988)
* fix: deduplicate Enable Banking API transactions with different entry_reference IDs (#954)

Enable Banking API sometimes returns the same logical transaction multiple
times with different entry_reference values in a single response. This causes
duplicate entries because the existing ID-based deduplication treats them as
distinct transactions.

Add content-based deduplication that compares (date, amount, currency,
creditor, debtor, remittance_information, status) to detect and remove these
API-level duplicates before storing them. The first occurrence is kept.

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

* test: add Enable Banking processor and importer deduplication tests (#954)

Add tests for:
- EnableBankingEntry::Processor: verifies entry_reference fallback for
  external_id, idempotent re-processing, string key handling
- EnableBankingItem::Importer: verifies content-based deduplication removes
  API-level duplicates while preserving legitimate distinct transactions

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

* fix: handle nil values in remittance_information array for dedup key (#954)

Call compact and map(&:to_s) before sort.join when remittance_information
is an array, preventing ArgumentError when it contains nil elements.
Also document the known limitation of content-based deduplication
collapsing genuinely distinct identical transactions.

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

* test: add coverage for nil values in remittance_information array (#954)

Verify that deduplication handles remittance_information arrays containing
nil elements without raising ArgumentError, and correctly treats arrays
with different nil positions but same non-nil content as duplicates.

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

* fix: prefer transaction_id over content-based dedup to preserve legit duplicates (#954)

When transaction_id is present, use it as the dedup key instead of falling
back to content-based deduplication. This preserves legitimately distinct
transactions with identical content (e.g. two laundromat payments of the
same amount on the same day) while still deduplicating the Enable Banking
duplicate entry_reference issue when transaction_id is nil.

Addresses review feedback from @jjmata about legitimate duplicate
transactions being incorrectly collapsed.

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

* fix: use composite key for dedup instead of transaction_id alone (#954)

Per the Enable Banking API docs, transaction_id is not guaranteed to be
unique. Include it as one component of the composite content key rather
than using it as the sole dedup criterion. This preserves transactions
with non-unique transaction_ids but different content, while still
deduplicating true API-level duplicates.

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

* test: add value_date fallback coverage for dedup key (#954)

build_transaction_content_key falls back to value_date when booking_date
is absent. This test exercises that path.

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

* docs: document known limitation of content-based dedup (#954)

When transaction_id is nil for both transactions, pure content comparison
applies, which could theoretically collapse two genuinely distinct
transactions with identical fields. Document this trade-off inline for
future maintainers.

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

* fix: add credit_debit_indicator to dedup composite key (#954)

transaction_amount.amount is always positive in the Enable Banking API,
with direction encoded separately in credit_debit_indicator (CRDT/DBIT).
Without it in the composite key, a payment and a same-day refund of the
same amount to the same merchant would produce identical keys, silently
dropping one transaction.

- Add credit_debit_indicator to build_transaction_content_key
- Add test for payment + same-day refund scenario
- Update docstring to document the rationale

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-28 16:53:30 +01:00
Juan Manuel Reyes
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
9410e5b38d Providers sharing (#1273)
* third party provider scoping

* Simplify logic and allow only admins to mange providers

* Broadcast fixes

* FIX tests and build

* Fixes

* Reviews

* Scope merchants

* DRY fixes
2026-03-25 17:47:04 +01:00