Commit Graph

1286 Commits

Author SHA1 Message Date
LPW
ee6afb48fd Add encryption support to provider account models (#815)
* Enable encryption for raw payloads in account models.

* Add backfill support for Snaptrade, Coinbase, Coinstats, and Mercury accounts.
2026-02-04 23:40:01 +01:00
David Gil
b08285a10f API v1: add amount_cents + signed_amount_cents to transactions (#899)
* feat(api): add amount_cents + signed_amount_cents to transactions

* fix: use currency.minor_unit_conversion for amount_cents

- Replace hardcoded *100 with currency.minor_unit_conversion
- Handles JPY (0 decimals), KWD/BHD (3 decimals), etc. correctly
- Add assert_amount_cents_fields helper to validate sign/scale invariants
2026-02-04 22:55:50 +01:00
Juan José Mata
0fb9d60ee6 Use dependent: :purge_later for ActiveRecord attachments (#882)
* Use dependent: :purge_later for user profile_image cleanup

This is a simpler alternative to PR #787's callback-based approach.
Instead of adding a custom callback and method, we use Rails' built-in
`dependent: :purge_later` option which is already used by FamilyExport
and other models in the codebase.

This single-line change ensures orphaned ActiveStorage attachments are
automatically purged when a user is destroyed, without the overhead of
querying all attachments manually.

https://claude.ai/code/session_01Np3deHEAJqCBfz3aY7c3Tk

* Add dependent: :purge_later to all ActiveStorage attachments

Extends the attachment cleanup from PR #787 to cover ALL models with
ActiveStorage attachments, not just User.profile_image.

Models updated:
- PdfImport.pdf_file - prevents orphaned PDF files from imports
- Account.logo - prevents orphaned account logos
- PlaidItem.logo, SimplefinItem.logo, SnaptradeItem.logo,
  CoinstatsItem.logo, CoinbaseItem.logo, LunchflowItem.logo,
  MercuryItem.logo, EnableBankingItem.logo - prevents orphaned
  provider logos

This ensures that when a family is deleted (cascade from last user
purge), all associated storage files are properly cleaned up via
Rails' built-in dependent: :purge_later mechanism.

https://claude.ai/code/session_01Np3deHEAJqCBfz3aY7c3Tk

* Make sure `Provider` generator adds it

* Fix tests

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-03 15:45:25 +01:00
tlink
9a9ebb147b Add localization for onboarding goals across multiple languages (#873)
* Add localization for onboarding goals across multiple languages

* Add password requirements localization for multiple languages

* Refactor localization keys for authentication messages

* Add `oidc` localization key for multiple languages

* Add OIDC account localization for multiple languages

* Add localization for trial and profile setup across multiple languages

* Refactor OIDC button label fallback to prioritize label presence over localization key

* Refactor onboarding tests to use I18n for text assertions and button labels

* Linter

* Last test fix?!?

* We keep both `oidc` and `openid_connect` due to contatenation issues

---------

Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-02-03 14:49:21 +01:00
Jakub Kottnauer
011957b4cb Increase FX rate deviation tolerance to 10% when matching transfers (#877)
* Increase exchange rate deviation tolerance to 10% when matching transfers

* Fix test
2026-02-03 14:20:34 +01:00
MkDev11
0afdb1d0fd Feature/pdf import transaction rows (#846)
* Add import row generation from PDF extracted data

- Add generate_rows_from_extracted_data method to PdfImport
- Add import! method to create transactions from PDF rows
- Update ProcessPdfJob to generate rows after extraction
- Update configured?, cleaned?, publishable? for PDF workflow
- Add column_keys, required_column_keys, mapping_steps
- Set bank statements to pending status for user review
- Add tests for new functionality

Closes #844

* Add tests for BankStatementExtractor

- Test transaction extraction from PDF content
- Test deduplication across chunk boundaries
- Test amount normalization for various formats
- Test graceful handling of malformed JSON responses
- Test error handling for empty/nil PDF content

* Fix supports_pdf_processing? to validate effective model

The validation was always checking @default_model, but process_pdf
allows overriding the model via parameter. This could cause a
vision-capable override model to be rejected, or a non-vision-capable
override to pass validation only to fail during processing.

Changes:
- supports_pdf_processing? now accepts optional model parameter
- process_pdf passes effective model to validation
- Raise Provider::Openai::Error inside with_provider_response for
  consistent error handling

Addresses review feedback from PR#808

* Fix insert_all! bug: explicitly set import_id

Rails insert_all! on associations does NOT auto-set the foreign key.
Added import_id explicitly and use Import::Row.insert_all! directly.
Also reload rows before counting to ensure accurate count.

* Fix pending status showing as processing for bank statements with rows

When bank statement PDF imports have extracted rows, show a 'Ready for Review'
screen with a link to the confirm path instead of the 'Processing' spinner.

This addresses the PR feedback that users couldn't reach the review flow even
though rows were created.

* Gate publishable? on account.present? to prevent import failure

PDF imports are created without an account, and import! raises if account
is missing. This prevents users from hitting publish and having the job fail.

* Wrap generate_rows_from_extracted_data in transaction for atomicity

- Clear rows and reset count even when no transactions extracted
- Use transaction block to prevent partial updates on failure
- Use mapped_rows.size instead of reload for count

* Localize transactions count string with i18n helper

* Add AccountMapping step for PDF imports when account is nil

PDF imports need account selection before publishing. This adds
Import::AccountMapping to mapping_steps when account is nil,
matching the behavior of TransactionImport and TradeImport.

Addresses PR#846 feedback about account selection for PDF imports.

* Only include CategoryMapping when rows have non-empty categories

PDF extraction doesn't extract categories from bank statements,
so the CategoryMapping step would show empty. Now we only include
CategoryMapping if rows actually have non-empty category values.

This prevents showing an empty mapping step for PDF imports.

* Fix PDF import UI flow and account selection

- Add direct account selection in PDF import UI instead of AccountMapping
- AccountMapping designed for CSV imports with multiple account values
- PDF imports need single account for all transactions
- Add update action and route for imports controller
- Fix controller to handle pdf_import param format from form_with
- Show Publish button when import is publishable (account set)
- Fix stepper nav: Upload/Configure/Clean non-clickable for PDF imports
- Redirect PDF imports from configuration step (auto-configured)
- Improve AI prompt to recognize M-PESA/mobile money as bank statements
- Fix migration ordering for import_rows table columns

* Add guard for invalid account_id in imports#update

Prevents silently clearing account when invalid ID is passed.
Returns error message instead of confusing 'Account saved' notice.

* Localize step names in import nav and add account guard

- Use t() helper for all step names (Upload, Configure, Clean, Map, Confirm)
- Add guard for invalid account_id in imports#update
- Prevents silently clearing account when invalid ID is passed

* Make category column migrations idempotent

Check if columns exist before adding to prevent duplicate column
errors when migrations are re-run with new timestamps.

* Add match_path for PDF import step highlighting

Fixes step detection when path is nil by using separate match_path
for current step highlighting while keeping links disabled.

* Rename category migrations and update to Rails 7.2

- Rename class to EnsureCategoryFieldsOnImportRows to avoid conflicts
- Rename class to EnsureCategoryIconOnImportRows
- Update migration version from 7.1 to 7.2 per guidelines
- Rename files to match class names
- Add match_path for PDF import step highlighting

* Use primary (black) style for Create Account and Save buttons

* Remove match_path from auto-completed PDF steps

Only step 4 (Confirm) needs match_path for active-step detection.
Steps 1-3 are purely informational and always complete.

* Add fallback for document type translation

Handles nil or unexpected document_type values gracefully.
Also removes match_path from auto-completed PDF steps.

* Use index-based step number for mobile indicator

Fixes 'Step 5 of 4' issue when Map step is dynamically removed.

* Fix hostings_controller_test: use blank? instead of nil

Setting returns empty string not nil for unset values.

* Localize step progress label and use design token

* Fix button styling: use design system Tailwind classes

btn--primary and btn--secondary CSS classes don't exist.
Use actual design system classes from DS::Buttonish.

* Fix CRLF line endings in tags_controller_test.rb

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
2026-02-02 16:27:02 +01:00
Number Eight
408bdd6788 fix: transaction UI padding and mobile selection bar position (#847)
* style: adjust the bottom position of the transaction selection bar and remove unnecessary padding from transaction forms

* fix: prevent overlap with the navbar in PWA mode

* fix: prevent selection bar overlap with navbar in PWA mode

* Update _selection_bar.html.erb

Signed-off-by: Number Eight <55629655+CylonN8@users.noreply.github.com>

* Update _selection_bar.html.erb

Signed-off-by: Number Eight <55629655+CylonN8@users.noreply.github.com>

---------

Signed-off-by: Number Eight <55629655+CylonN8@users.noreply.github.com>
2026-02-01 23:50:39 +01:00
AdamWHY2K
ad386c6e27 fix: Lunchflow pending transaction duplicates, missing from search and filter (#859)
* fix: lunchflow parity with simplefin/plaid pending behaviour

* fix: don't suggest duplicate if both entries are pending

* refactor: reuse the same external_id for re-synced pending transactions

* chore: replace illogical duplicate collision test with multiple sync test

* fix: prevent duplicates when users edit pending lunchflow transactions

* chore: add test for preventing duplicates when users edit pending lunchflow transactions

* fix: normalise extra hash keys for pending detection
2026-02-01 23:48:54 +01:00
Juan José Mata
70f483c603 Add tests for uncategorized transaction filter across locales (#862)
* test: Add tests for uncategorized filter across all locales

Adds two tests to catch the bug where filtering for "Uncategorized"
transactions fails when the user's locale is not English:

1. Tests that filtering with the locale-specific uncategorized name
   works correctly in all SUPPORTED_LOCALES
2. Tests that filtering with the English "Uncategorized" parameter
   works regardless of the current locale (catches the French bug)

https://claude.ai/code/session_01JcKj4776k5Es8Cscbm4kUo

* fix: Fix uncategorized filter for French, Catalan, and Dutch locales

The uncategorized filter was failing when the URL parameter contained
"Uncategorized" (English) but the user's locale was different. This
affected 3 locales with non-English translations:
- French: "Non catégorisé"
- Catalan: "Sense categoria"
- Dutch: "Ongecategoriseerd"

The fix adds Category.all_uncategorized_names which returns all possible
uncategorized name translations across supported locales, and updates
the search filter to check against all variants instead of just the
current locale's translation.

https://claude.ai/code/session_01JcKj4776k5Es8Cscbm4kUo

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-01 18:59:12 +01:00
Alessio Cappa
ea0c70de8a fix: Fix layout UI issues for rule creation (#852)
* fix: Fix layout UI issues for rule creation

* Update app/views/rule/conditions/_condition.html.erb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

* Update app/views/rule/actions/_action.html.erb

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>

---------

Signed-off-by: Alessio Cappa <104093777+alessiocappa@users.noreply.github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
2026-01-31 18:22:54 +01:00
sentry[bot]
8a8ae54954 refactor: Use first! for transfer lookup (#837)
Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com>
2026-01-31 09:50:40 +01:00
Abdallatif Sulaiman
ea80e92b6b Add Palestine to country options in preferences (#845)
Co-authored-by: Abdallatif Sulaiman <asulaiman@restaurant365.com>
2026-01-31 09:45:39 +01:00
Dream
5d06112281 Fix budget category totals to account for refunds and reimbursements (#824)
* Fix budget category totals to net refunds against expenses

Budget spending calculations now subtract refunds (negative transactions
classified as income) from expense totals in the same category. Previously,
refunds were excluded entirely, causing budgets to show gross spending
instead of net spending.

Fixes #314

* Handle missing git binary in commit_sha initializer

Rescues Errno::ENOENT when git is not installed, falling back to
BUILD_COMMIT_SHA env var or "unknown". Fixes crash in Docker
development containers that lack git.

* Revert "Handle missing git binary in commit_sha initializer"

This reverts commit 7e58458faa.

* Subtract uncategorized refunds from overall budget spending

Uncategorized refunds were not being netted against actual_spending
because the synthetic uncategorized category has no persisted ID and
wasn't matched by the budget_categories ID set. Now checks for
category.uncategorized? in addition to the ID lookup.

* perf: optimize budget category actual spending calculation
2026-01-31 09:41:28 +01:00
MkDev11
6f8858b1a6 feat/Add AI-Powered Bank Statement Import (step 1, PDF import & analysis) (#808)
* feat: Add PDF import with AI-powered document analysis

This enhances the import functionality to support PDF files with AI-powered
document analysis. When a PDF is uploaded, it is processed by AI to:
- Identify the document type (bank statement, credit card statement, etc.)
- Generate a summary of the document contents
- Extract key metadata (institution, dates, balances, transaction count)

After processing, an email is sent to the user asking for next steps.

Key changes:
- Add PdfImport model for handling PDF document imports
- Add Provider::Openai::PdfProcessor for AI document analysis
- Add ProcessPdfJob for async PDF processing
- Add PdfImportMailer for user notification emails
- Update imports controller to detect and handle PDF uploads
- Add PDF import option to the new import page
- Add i18n translations for all new strings
- Add comprehensive tests for the new functionality

* Add bank statement import with AI extraction

- Create ImportBankStatement assistant function for MCP
- Add BankStatementExtractor with chunked processing for small context windows
- Register function in assistant configurable
- Make PdfImport#pdf_file_content public for extractor access
- Increase OpenAI request timeout to 600s for slow local models
- Increase DB connection pool to 20 for concurrent operations

Tested with M-Pesa bank statement via remote Ollama (qwen3:8b):
- Successfully extracted 18 transactions
- Generated CSV and created TransactionImport
- Works with 3000 char chunks for small context windows

* Add pdf-reader gem dependency

The BankStatementExtractor uses PDF::Reader to parse bank statement
PDFs, but the gem was not properly declared in the Gemfile. This would
cause NameError in production when processing bank statements.

Added pdf-reader ~> 2.12 to Gemfile dependencies.

* Fix transaction deduplication to preserve legitimate duplicates

The previous deduplication logic removed ALL duplicate transactions based
on [date, amount, name], which would drop legitimate same-day duplicates
like multiple ATM withdrawals or card authorizations.

Changed to only deduplicate transactions that appear in consecutive chunks
(chunking artifacts) while preserving all legitimate duplicates within the
same chunk or non-adjacent chunks.

* Refactor bank statement extraction to use public provider method

Address code review feedback:
- Add public extract_bank_statement method to Provider::Openai
- Remove direct access to private client via send(:client)
- Update ImportBankStatement to use new public method
- Add require 'set' to BankStatementExtractor
- Remove PII-sensitive content from error logs
- Add defensive check for nil response.error
- Handle oversized PDF pages in chunking logic
- Remove unused process_native and process_generic methods
- Update email copy to reflect feature availability
- Add guard for nil document_type in email template
- Document pdf-reader gem rationale in Gemfile

Tested with both OpenAI (gpt-4o) and Ollama (qwen3:8b):
- OpenAI: 49 transactions extracted in 30s
- Ollama: 40 transactions extracted in 368s
- All encapsulation and error handling working correctly

* Update schema.rb with ai_summary and document_type columns

* Address PR #808 review comments

- Rename :csv_file to :import_file across controllers/views/tests
- Add PDF test fixture (sample_bank_statement.pdf)
- Add supports_pdf_processing? method for graceful degradation
- Revert unrelated database.yml pool change (600->3)
- Remove month_start_day schema bleed from other PR
- Fix PdfProcessor: use .strip instead of .strip_heredoc
- Add server-side PDF magic byte validation
- Conditionally show PDF import option when AI provider available
- Fix ProcessPdfJob: sanitize errors, handle update failure
- Move pdf_file attachment from Import to PdfImport
- Document deduplication logic limitations
- Fix ImportBankStatement: catch specific exceptions only
- Remove unnecessary require 'set'
- Remove dead json_schema method from PdfProcessor
- Reduce default OpenAI timeout from 600s to 60s
- Fix nil guard in text mailer template
- Add require 'csv' to ImportBankStatement
- Remove Gemfile pdf-reader comment

* Fix RuboCop indentation in ProcessPdfJob

* Refactor PDF import check to use model predicate method

Replace is_a?(PdfImport) type check with requires_csv_workflow? predicate
that leverages STI inheritance for cleaner controller logic.

* Fix missing 'unknown' locale key and schema version mismatch

- Add 'unknown: Unknown Document' to document_types locale
- Fix schema version to match latest migration (2026_01_24_180211)

* Document OPENAI_REQUEST_TIMEOUT env variable

Added to .env.local.example and docs/hosting/ai.md

* Rename ALLOWED_MIME_TYPES to ALLOWED_CSV_MIME_TYPES for clarity

* Add comment explaining requires_csv_workflow? predicate

* Remove redundant required_column_keys from PdfImport

Base class already returns [] by default

* Add ENV toggle to disable PDF processing for non-vision endpoints

OPENAI_SUPPORTS_PDF_PROCESSING=false can be used for OpenAI-compatible
endpoints (e.g., Ollama) that don't support vision/PDF processing.

* Wire up transaction extraction for PDF bank statements

- Add extracted_data JSONB column to imports
- Add extract_transactions method to PdfImport
- Call extraction in ProcessPdfJob for bank statements
- Store transactions in extracted_data for later review

* Fix ProcessPdfJob retry logic, sanitize and localize errors

- Allow retries after partial success (classification ok, extraction failed)
- Log sanitized error message instead of raw message to avoid data leakage
- Use i18n for user-facing error messages

* Add vision-capable model validation for PDF processing

* Fix drag-and-drop test to use correct field name csv_file

* Schema bleedover from another branch

* Fix drag-drop import form field name to match controller

* Add vision capability guard to process_pdf method

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-01-30 20:44:25 +01:00
Pere Montpeó
9f5fdd4d13 feat: add valuations API endpoints for managing account reconciliations (#745)
* feat: add valuations API endpoints for managing account reconciliations

* refactor: formatting

* fix: make account extraction clearer

* feat: validation and error handling improvements

* feat: transaction

* feat: error handling

* Add API documentation LLM context

* Make it easier for people

* feat: transaction in creation

* feat: add OpenAPI spec for Valuations API

* fix: update notes validation to check for key presence

* Prevent double render

* All other docs use `apiKeyAuth`

* More `apiKeyAuth`

* Remove testing assertions from API doc specs

* fix: correct valuation entry references

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-30 18:54:15 +01:00
Juan José Mata
02cd84568e Add deterministic API key for uptime monitoring (#834)
* Preserve existing demo data by default

Add SKIP_CLEAR environment variable to demo_data rake tasks.
Defaults to true (preserving existing data). Set SKIP_CLEAR=0
to wipe data before generating new demo data.

https://claude.ai/code/session_01GcoMc2SH3czPrbeGkHbmpE

* Add deterministic instatus.com API key for demo data

Create a read-only API key named "instatus.com" with a fixed value
when generating demo data. This allows uptime monitoring tools to
use a hardcoded API key that doesn't change between demo data runs.

The key is idempotent - if it already exists, it will be reused.

https://claude.ai/code/session_01GcoMc2SH3czPrbeGkHbmpE

* OK to name instatus to a point

* Remove all Instatus references

* Rename to create_monitoring_api_key! and scope lookup to admin_user

- Rename create_instatus_api_key! to create_monitoring_api_key! (snake_case)
- Scope API key lookup to admin_user instead of global ApiKey lookup
- Each family's admin now has their own monitoring API key

https://claude.ai/code/session_01GcoMc2SH3czPrbeGkHbmpE

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-30 12:29:46 +01:00
Alessio Cappa
47897fadd0 feat: Change protected indicator styling (#828)
* feat: Change protected indicator styling

* fix: apply review comment
2026-01-30 12:20:30 +01:00
StalkerSea
a86329d632 PWA: Update manifest, meta tags, and fix UI layout issues (#801)
* pwa(cleanup): enforce LF, head meta + icons, manifest orientation, remove static webmanifest

* pwa(cleanup): add gitattributes, head meta/icons, manifest orientation; remove static manifest; small nav & dashboard fixes

* pwa(cleanup): improve transaction drawer header layout with inline close button

* fix: address PR review feedback

- Add dom_id to transaction header for Turbo Stream updates (Codex)
- Add pending badge next to date when transaction is pending (CodeRabbit)
- Make close button keyboard-focusable by removing tabindex=-1 (CodeRabbit)
- Fix settings nav horizontal scroll with flex-nowrap space-x-1 (CodeRabbit)

* fix: localize 'Linked with Plaid' tooltip string (CodeRabbit)

* Update .gitattributes

Better comment smh

* fix: align transaction/transfer dialog icons and update transfer drawer pattern

- Fix icon alignment in transaction header (items-center instead of items-start)
- Make transfer/linked icons consistent size and color
- Update transfers/show.html.erb to use frame: drawer with hide_close_icon pattern
- Match transfer dialog header layout with transaction details

* fix: enhance header layout

This in the transaction and transfer views, with consistent icon placement

* fix: remove fixed height from HTML document class

basically a regression issue pretty sure

* fix: update dialog rendering to use 'frame' and hide close icon in headers

* fix: update transaction type tabs layout for improved responsiveness

* fix: conditionally render transaction type tabs based on account type
2026-01-29 15:16:49 +01:00
Juan José Mata
bdfb0e64bc Add 'web' to valid device types
Flutter comes in as `web` when testing / using the Chrome profile

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-29 13:12:05 +01:00
Juan José Mata
f6c38344cd Update PostHog script configuration settings
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-28 00:46:06 +01:00
MkDev11
eeff4edbea Add warning for TwelveData plan-restricted tickers (#803)
* Add warning for TwelveData plan-restricted tickers

Fixes #800

- Add Security::PlanRestrictionTracker concern using Rails cache
- Detect plan upgrade errors during Security::Price::Importer sync
- Display amber warning on /settings/hosting with affected tickers
- Include unit tests for the new functionality

* Scope plan restriction cache by provider

Addresses review feedback:
- Cache key now includes provider name to support multiple data providers
- Methods now require provider parameter for proper scoping
- Added tests for provider-scoped restrictions
- Added documentation explaining instance-level API key architecture

* Fix RuboCop array bracket spacing

* Fix empty array bracket spacing

* Move plan upgrade detection to Provider::TwelveData

* Fix provider scoping tests to use direct cache writes

---------

Co-authored-by: mkdev11 <jaysmth689+github@users.noreply.github.com>
2026-01-27 15:45:50 +01:00
Alessio Cappa
aef582f553 feat: Move upcoming recurring transactions in a dedicated tab (#771)
* feat: Move upcoming transactions in a dedicated tab

* Adjust formatting

* feat: adjust visibility on mobile

* feat: change translation label

* feat: show only upcoming transactions expected in the next 10 days

* feat: show upcoming transactions tab only when option enabled

* feat: render empty partial when there are no recurring transactions

* feat: align icon sizing and spacing between transactions and upcoming sections

* feat: add missing localitazion labels

* fix: move filter on upcoming transactions in controller

* fix: add missing localitazion labels
2026-01-27 12:32:35 +01:00
charsel
33df3b781e fix: Handle uncategorized transactions filter correctly (#802)
* fix: Handle uncategorized transactions filter correctly

When filtering for 'Uncategorized' transactions, the filter was not working
because 'Uncategorized' is a virtual category (Category.uncategorized returns
a non-persisted Category object) and does not exist in the database.

The filter was attempting to match 'categories.name IN (Uncategorized)' which
returned zero results.

This fix removes 'Uncategorized' from the category names array before querying
the database, allowing the existing 'category_id IS NULL' condition to work
correctly.

Fixes filtering for uncategorized transactions while maintaining backward
compatibility with all other category filters.

* test: Add comprehensive tests for Uncategorized filter

- Test filtering for only uncategorized transactions
- Test combining uncategorized with real categories
- Test excluding uncategorized when not in filter
- Ensures fix prevents regression

* refactor: Use Category.uncategorized.name for i18n support

- Replace hard-coded 'Uncategorized' string with Category.uncategorized.name
- Conditionally build SQL query based on include_uncategorized flag
- Avoid adding category_id IS NULL clause when not needed
- Update tests to use Category.uncategorized.name for consistency
- Cleaner logic: only include uncategorized condition when requested

Addresses code review feedback on i18n support and query optimization.

* test: Fix travel category fixture error

Create travel category dynamically instead of using non-existent fixture

* style: Fix rubocop spacing in array brackets

---------

Co-authored-by: Charsel <charsel@charsel.com>
2026-01-27 12:28:33 +01:00
Juan José Mata
946d0cb3ef Merge branch 'main' into feature/llm-cache-reset
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-27 08:50:01 +01:00
Dream
51579d3731 FR: Add transaction type as rule condition option (#790)
* Add transaction type condition filter for rules

Add ability to filter rules by transaction type (income, expense, transfer).
This allows users to create rules that differentiate between transactions
with the same name but different types.

- Add Rule::ConditionFilter::TransactionType with select dropdown
- Register in TransactionResource condition_filters
- Add tests for income, expense, and transfer filtering

Closes #373

* Address PR review feedback for transaction type filter

- Fix income filter to exclude transfers and investment_contribution
- Fix expense filter to include investment_contribution regardless of sign
- Add i18n for option and operator labels
- Add tests for edge cases (transfer inflows, investment contributions)

Logic now matches Transaction::Search#apply_type_filter for consistency.
2026-01-26 16:53:05 +01:00
Fabien Le Frapper
4d867c193c Increase min year for home built (#783) 2026-01-26 10:26:48 +01:00
eureka928
23e9749ed1 Refactor clear_ai_cache to use family_scope pattern
- Move family-scoped queries to models via family_scope class method
- Remove hardcoded model names from Enrichable concern
- Replace inline rescue with proper respond_to? check
- Add count tracking for better logging
2026-01-26 10:17:28 +01:00
eureka928
029d09685e Address PR review feedback
- Preserve user locks: Only unlock attributes where current value still matches
  what AI set. If user changed the value, they took ownership.
- Add nil guard clause for family parameter in ClearAiCacheJob
- Add partial failure handling so one model's failure doesn't block the other
2026-01-26 10:14:06 +01:00
eureka928
ed8185cf2b Optimize clear_ai_cache to batch unlock attributes
Replace N individual update calls with single update_column for better performance.
2026-01-26 09:50:05 +01:00
eureka928
b82757f58e Use i18n for AI cache reset strings
Extract hardcoded strings to locale file for proper internationalization.
2026-01-26 09:49:05 +01:00
eureka928
329fe9832a Add Reset AI cache button to rules index
Add menu button with confirmation dialog to reset AI cache. Fix menu_item to safely handle non-standard confirm values.
2026-01-26 09:46:31 +01:00
eureka928
b511b3add9 Add clear_ai_cache endpoint to rules controller
Add POST /rules/clear_ai_cache route and controller action to trigger AI cache clearing for the current family.
2026-01-26 09:46:26 +01:00
eureka928
46ab1d8373 Add AI cache clearing infrastructure
Add ClearAiCacheJob for async cache clearing with low priority. Extend Enrichable concern with clear_ai_cache methods to unlock AI-enriched attributes and delete AI enrichment records. Trigger automatic cache clearing when OpenAI model setting changes.
2026-01-26 09:46:20 +01:00
Alessio Cappa
27fdfca595 fix: remove fixed height on tags field in bulk update (#778) 2026-01-25 18:31:57 +01:00
Alessio Cappa
2bb98b837a fix: Add border to merchant logo (#776) 2026-01-25 18:30:12 +01:00
Juan José Mata
c7ab25b866 Use browser Accept-Language for login and onboarding locale (#768)
* Use Accept-Language for unauthenticated locale

* Add per-user locale overrides

* Fix test

* Use more than the top `accept-language` entry

* Localization of string
2026-01-24 22:00:41 +01:00
LPW
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
Alessio Cappa
1b514f63e4 feat: Display shared budget as a badge (#756)
* feat: display shared budget as a badge

* fix: reduce margin on badge

* fix: adjust mobile spacing

* Consistent opacity

Signed-off-by: Juan José Mata <jjmata@jjmata.com>

---------

Signed-off-by: Juan José Mata <jjmata@jjmata.com>
Co-authored-by: Juan José Mata <jjmata@jjmata.com>
2026-01-24 12:33:17 +01:00
LPW
d98711d4ea Rename raw_investments_payload to raw_holdings_payload for Plaid accounts (#760)
* refactor: rename `raw_investments_payload` to `raw_holdings_payload`

- Update references and models to use consistent naming.
- Adjust migrations, tests, and encryption setup accordingly.

* fix: improve safety when accessing raw_holdings_payload keys

- Use `dig` with safe navigation to prevent potential nil errors.
- Add support for decryption from the old column name `raw_investments_payload`.
- Adjust related methods and calculations for consistency.

---------

Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
2026-01-24 11:16:26 +01:00
LPW
8c9764f1ad Unify provider and account card UI and move setup actions to menus (#755)
* feat: add auto-open functionality for collapsible sections and streamline unlinked account handling

- Introduce `auto-open` Stimulus controller to auto-expand <details> elements based on URL params.
- Update all settings sections and panels to support the new `auto_open_param` for seamless navigation.
- Improve unlinked account logic for Coinbase, SimpleFIN, and SnapTrade, ensuring consistent and optimized handling.
- Refactor sync warnings and badges for better readability and user experience.
- Extend localization for additional menu items, warnings, and setup prompts.

* fix: improve error handling and safe HTML usage in Coinbase and settings components

- Log warning for unhandled exceptions in Coinbase unlinked account count fallback.
- Escape `auto_open_param` in settings section for safe HTML injection.
- Clean up URL params in `auto-open` controller after auto-expansion.

---------

Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
2026-01-24 01:11:56 +01:00
Juan José Mata
32793ff8b4 fix: Enable scrolling on login page for small mobile devices (#754)
* fix: Enable scrolling on login page for small mobile devices

Changed auth layout containers from `h-full` to `min-h-full` and added
`overflow-y-auto` to allow content to scroll when it exceeds viewport
height on small mobile phones.

* Real fix

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 23:05:45 +01:00
Mark Hendriksen
9b84c5bdbc Enhanced Import Amount Type Selection (#506)
* Enhanced Import Amount Type Selection

updated version of https://github.com/we-promise/sure/pull/179

* copilot sugestions

* ai sugestions

* Update import.rb

* Update schema.rb

* Update schema.rb

* Update schema.rb

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-23 22:12:02 +01:00
soky srm
696ff0966b Initial security fixes (#461)
* Initial sec

* Update PII fields

* FIX add tests

* FIX safely read plaintext data on rake backfill

* Update user.rb

* FIX tests

* encryption_ready? block

* Test conditional to encryption on

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-23 22:05:28 +01:00
Juan José Mata
71f10c5e4a fix: Handle missing encryption keys gracefully on Poviders config page (#753)
* fix: Handle missing encryption keys gracefully on providers page

When Active Record encryption keys are not configured, the settings/providers
page would crash with an unhandled exception. This change catches the
ActiveRecord::Encryption::Errors::Configuration error and displays a
friendly error message instead, explaining that encryption credentials
need to be configured before using sync providers.

https://claude.ai/code/session_015nPsLWkr12i5ok5bwLtA7p

* Simplify rescue block

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 19:15:04 +01:00
Juan José Mata
6b5a5b1877 fix: Show cancellation message when subscription is pending cancellation (#752)
* fix: Show cancellation message when subscription is pending cancellation

When a subscription is cancelled via Stripe, the UI incorrectly showed
"Your contribution continues on..." instead of reflecting the cancellation
status. This fix adds tracking of `cancel_at_period_end` from Stripe webhooks
and displays "Your contribution ends on..." when a subscription has been
cancelled but is still active until the billing period ends.

https://claude.ai/code/session_01Y8ELTdK1k9o315iSq43TRN

* chore: Update schema.rb with cancel_at_period_end column

https://claude.ai/code/session_01Y8ELTdK1k9o315iSq43TRN

* Schema version

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 18:55:51 +01:00
LPW
c504ba9b99 Add security remapping for holdings with sync protection (#692)
* Add security remapping support to holdings

- Introduced `provider_security` tracking for holdings with schema updates.
- Implemented security remap/reset workflows in `Holding` model and UI.
- Updated routes, controllers, and tests to support new functionality.
- Enhanced client-side interaction with Stimulus controller for remapping.

# Conflicts:
#	app/components/UI/account/activity_feed.html.erb
#	db/schema.rb

* Refactor "New transaction" to "New activity" across UI and tests

- Updated localized strings, button labels, and ARIA attributes.
- Improved error handling in holdings' current price display.
- Scoped fallback queries in `provider_import_adapter` to prevent overwrites.
- Added safeguard for offline securities in price fetching logic.

* Update security remapping to merge holdings on collision by deleting duplicates

- Removed error handling for collisions in `remap_security!`.
- Added logic to merge holdings by deleting duplicates on conflicting dates.
- Modified associated test to validate merging behavior.

* Update security remapping to merge holdings on collision by combining qty and amount

- Modified `remap_security!` to merge holdings by summing `qty` and `amount` on conflicting dates.
- Adjusted logic to calculate `price` for merged holdings.
- Updated test to validate new merge behavior.

* Improve DOM handling in Turbo redirect action & enhance holdings merge logic

- Updated Turbo's custom `redirect` action to use the "replace" option for cleaner DOM updates without clearing the cache.
- Enhanced holdings merge logic to calculate weighted average cost basis during security remapping, ensuring more accurate cost_basis updates.

* Track provider_security_id during security updates to support reset workflows

* Fix provider tracking: guard nil ticker lookups and preserve merge attrs

- Guard fallback 1b lookup when security.ticker is blank to avoid matching NULL tickers
- Preserve external_id, provider_security_id, account_provider_id during collision merge

* Fix schema.rb version after merge (includes tax_treatment migration)

* fix: Rename migration to run after schema version

The migration 20260117000001 was skipped in CI because it had a timestamp
earlier than the schema version (2026_01_17_200000). CI loads schema.rb
directly and only runs migrations with versions after the schema version.

Renamed to 20260119000001 so it runs correctly.

* Update schema: remove Coinbase tables, add new fields and indexes

* Update schema: add back `tax_treatment` field with default value "taxable"

* Improve Turbo redirect action: use "replace" to avoid form submission in history

* Lock merged holdings to prevent provider overwrites and fix activity feed template indentation

* Refactor holdings transfer logic: enforce currency checks during collisions and enhance merge handling

---------

Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Co-authored-by: luckyPipewrench <luckypipewrench@proton.me>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-23 12:54:55 +01:00
Juan José Mata
e0fb585bda Hide contribution payments from demo user(s) (#738)
* Hide payment contribution options from demo and manually created users

Demo data users and manually created users don't have stripe_customer_id
set on their family, so they should not see payment/contribution options.

Changes:
- Add can_manage_subscription? method to Family::Subscribeable that checks
  for presence of stripe_customer_id
- Guard Settings::PaymentsController to return 403 for users without
  stripe_customer_id
- Guard SubscriptionsController#show action (Stripe portal redirect) for
  users without stripe_customer_id
- Update settings navigation to hide the payment link when
  stripe_customer_id is not present
- Add tests for the new behavior

* Fix broken test

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 12:35:49 +01:00
Juan José Mata
5ba051c8cf fix: Broken /terms and /privacy routes (#749)
* fix: replace invalid redirect("about:blank") with proper controller actions

The privacy and terms routes were using redirect("about:blank") which is
invalid because about:blank is a browser-specific pseudo URL, not a valid
HTTP redirect target. This fix replaces them with proper controller actions
that render placeholder pages.

Changes:
- Add privacy and terms actions to PagesController with skip_authentication
- Create privacy.html.erb and terms.html.erb view templates
- Add i18n translations for the new pages
- Update routes to use pages#privacy and pages#terms

https://claude.ai/code/session_01RL36dMda1o6LXGsnGnTJZu

* Make legal routes configurable

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-23 11:39:48 +01:00
Dream
0316b848eb fix: add auto-refresh for processing exports on index page (#715)
Wrap export list in turbo_frame_tag with conditional polling attributes.
When exports are pending/processing, page polls every 3 seconds for updates.
Add turbo_frame: _top to download/delete buttons for proper frame handling.
2026-01-23 11:08:38 +01:00
Jose
69d9f51d57 # test(api): Add request specs for merchants and tags endpoints (#645)
* Add files via upload

Signed-off-by: Jose <39016041+jospaquim@users.noreply.github.com>

* Add merchants and tags resources to routes

Signed-off-by: Jose <39016041+jospaquim@users.noreply.github.com>

* update

* update spaces

* fix: Apply CodeRabbit suggestions and add YARD documentation

* docs: Add API documentation for merchants and tags endpoints

* fix: Address CodeRabbit feedback on documentation

* fix: Use authorize_scope! instead of ensure_read_scope

* test(api): Add request specs for merchants and tags endpoints

* test(api): Add request specs for merchants and tags endpoints

* test(api): Convert specs to Minitest format in test/

* fix: Correct indentation for private methods

* fix: merchant and tag test

* Enhance tag tests for family scope and access

Added tests to ensure tags from other families are not returned and that attempts to access them return 404.

Signed-off-by: Jose <39016041+jospaquim@users.noreply.github.com>

* Enhance merchants controller tests for family scope

Added tests to ensure that merchants from other families are not returned in the index action and that accessing a merchant from another family returns a 404 error.

Signed-off-by: Jose <39016041+jospaquim@users.noreply.github.com>

* Fix test/implementation

* Remove old token test code

* Improve test

---------

Signed-off-by: Jose <39016041+jospaquim@users.noreply.github.com>
Co-authored-by: Juan José Mata <juanjo.mata@gmail.com>
2026-01-23 10:18:22 +01:00