Skip to content

Honor per-currency decimal places across app#6954

Open
StephenBrown2 wants to merge 2 commits intoactualbudget:masterfrom
StephenBrown2:push-woswwuqwuwru
Open

Honor per-currency decimal places across app#6954
StephenBrown2 wants to merge 2 commits intoactualbudget:masterfrom
StephenBrown2:push-woswwuqwuwru

Conversation

@StephenBrown2
Copy link
Copy Markdown
Contributor

@StephenBrown2 StephenBrown2 commented Feb 12, 2026

Sorry for yet another PR, but I noticed that Vietnamese Dong got added with the wrong decimal places, due to the longstanding issue with not handling other than 2 decimal places.

I originally included sync-server adapter work here, but that was decided to be out of scope, so this PR now focuses on desktop-client + loot-core currency precision only.

Summary

This PR fixes the "everything assumes 2 decimal places" problem.

Amounts now use each currency's decimalPlaces across account creation, transaction editing/table flows, search/formula paths, and budget-related UI code. This avoids the x10/x100/x1000 inflation issues when using zero-decimal or three-decimal currencies.

I also corrected VND metadata to use decimalPlaces: 0.

IMPORTANT: If this is merged and released at the same time as #6902, there will be no db migration needed. If after, a DB migration MAY be needed to fix the 100x issue on existing values.

Tests added/updated

  • Added transaction table round-trip tests for:
    • zero-decimal currencies
    • three-decimal currencies
    • existing two-decimal default behavior (packages/desktop-client/src/components/transactions/table/utils.test.ts)
  • Added utility tests for decimal-aware formatting helpers:
    • integerToCurrencyWithDecimal
    • appendDecimals (packages/loot-core/src/shared/util.test.ts)
  • Added E2E coverage for zero-decimal account flows (JPY, VND):
    • starting balance remains stable
    • close-account modal shows the correct balance text (packages/desktop-client/e2e/accounts.test.ts)
  • Updated E2E snapshots for account creation to check that the starting balance bug mentioned in feat(currency): Add Vietnamese Dong (VND) currency #6902 is fixed.

Issues addressed

This PR is aimed at the non-2-decimal currency requests:

Test plan

  • yarn test
  • yarn typecheck
  • Manual smoke test with a zero-decimal currency (for example JPY / VND)

AI assistance

This change was made with the help of GPT-5.3 Codex.


Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 26 11.99 MB → 12 MB (+9.51 kB) +0.08%
loot-core 1 4.83 MB → 4.83 MB (+3.25 kB) +0.07%
api 4 4.06 MB → 4.06 MB (+3.19 kB) +0.08%
cli 1 7.88 MB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
26 11.99 MB → 12 MB (+9.51 kB) +0.08%
Changeset
File Δ Size
src/components/mobile/transactions/FocusableAmountInput.tsx 📈 +4.15 kB (+34.03%) 12.19 kB → 16.33 kB
src/components/transactions/table/utils.ts 📈 +359 B (+19.70%) 1.78 kB → 2.13 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +1.14 kB (+12.83%) 8.87 kB → 10.01 kB
src/queries/index.ts 📈 +252 B (+11.80%) 2.08 kB → 2.33 kB
src/hooks/useTransactionsSearch.ts 📈 +98 B (+9.29%) 1.03 kB → 1.13 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts 📈 +268 B (+4.51%) 5.81 kB → 6.07 kB
src/components/budget/envelope/CoverMenu.tsx 📈 +193 B (+4.00%) 4.71 kB → 4.9 kB
src/components/modals/EditFieldModal.tsx 📈 +297 B (+3.69%) 7.85 kB → 8.14 kB
src/components/modals/TrackingBudgetMenuModal.tsx 📈 +193 B (+3.11%) 6.07 kB → 6.26 kB
src/components/modals/EnvelopeBudgetMenuModal.tsx 📈 +193 B (+3.10%) 6.07 kB → 6.26 kB
src/components/modals/CreateLocalAccountModal.tsx 📈 +185 B (+2.87%) 6.3 kB → 6.48 kB
src/components/autocomplete/CategoryAutocomplete.tsx 📈 +374 B (+2.38%) 15.36 kB → 15.73 kB
package.json 📈 +62 B (+1.88%) 3.22 kB → 3.28 kB
src/components/mobile/transactions/TransactionListItem.tsx 📈 +193 B (+1.47%) 12.81 kB → 13 kB
src/components/settings/Currency.tsx 📈 +274 B (+1.41%) 18.92 kB → 19.19 kB
src/components/budget/BalanceWithCarryover.tsx 📈 +121 B (+1.36%) 8.71 kB → 8.83 kB
src/components/mobile/transactions/TransactionEdit.tsx 📈 +752 B (+1.26%) 58.28 kB → 59.01 kB
src/components/accounts/BalanceHistoryGraph.tsx 📈 +108 B (+1.17%) 9 kB → 9.1 kB
src/components/modals/CloseAccountModal.tsx 📈 +114 B (+1.10%) 10.16 kB → 10.27 kB
src/hooks/useFormulaExecution.ts 📈 +178 B (+1.05%) 16.63 kB → 16.8 kB
src/components/accounts/Account.tsx 📈 +374 B (+0.83%) 43.79 kB → 44.15 kB
src/components/transactions/TransactionsTable.tsx 📈 +700 B (+0.80%) 85.09 kB → 85.77 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +6 B (+0.56%) 1.05 kB → 1.05 kB
src/components/mobile/transactions/TransactionList.tsx 📈 +74 B (+0.41%) 17.54 kB → 17.61 kB
src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx 📈 +113 B (+0.36%) 30.77 kB → 30.88 kB
src/components/budget/util.ts 📈 +10 B (+0.30%) 3.24 kB → 3.25 kB
src/accounts/mutations.ts 📈 +34 B (+0.26%) 12.6 kB → 12.63 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/index.js 3.23 MB → 3.23 MB (+6.75 kB) +0.20%
static/js/useTransactionBatchActions.js 4.29 MB → 4.29 MB (+2.23 kB) +0.05%
static/js/TransactionList.js 81.29 kB → 81.55 kB (+267 B) +0.32%
static/js/ReportRouter.js 1021.25 kB → 1021.43 kB (+178 B) +0.02%
static/js/narrow.js 354.12 kB → 354.22 kB (+98 B) +0.03%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
static/js/BackgroundImage.js 119.98 kB 0%
static/js/FormulaEditor.js 846.44 kB 0%
static/js/ca.js 185.57 kB 0%
static/js/da.js 104.66 kB 0%
static/js/de.js 177.58 kB 0%
static/js/en-GB.js 7.16 kB 0%
static/js/en.js 170.68 kB 0%
static/js/es.js 172.13 kB 0%
static/js/fr.js 177.57 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 168.97 kB 0%
static/js/nb-NO.js 154.72 kB 0%
static/js/nl.js 111.58 kB 0%
static/js/pl.js 88.34 kB 0%
static/js/pt-BR.js 180.5 kB 0%
static/js/resize-observer.js 18.03 kB 0%
static/js/th.js 179.94 kB 0%
static/js/theme.js 30.68 kB 0%
static/js/uk.js 213.14 kB 0%
static/js/wide.js 418 B 0%
static/js/workbox-window.prod.es5.js 7.28 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 4.83 MB → 4.83 MB (+3.25 kB) +0.07%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts 📈 +352 B (+13.26%) 2.59 kB → 2.94 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts 📈 +1.2 kB (+4.91%) 24.49 kB → 25.69 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts 📈 +284 B (+4.52%) 6.14 kB → 6.42 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +207 B (+3.16%) 6.39 kB → 6.6 kB
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/transaction-rules.ts 📈 +539 B (+2.71%) 19.45 kB → 19.97 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts 📈 +239 B (+2.50%) 9.35 kB → 9.58 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts 📈 +196 B (+0.89%) 21.6 kB → 21.79 kB
home/runner/work/actual/actual/packages/loot-core/src/server/api.ts 📈 +185 B (+0.80%) 22.53 kB → 22.71 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/schedule-template.ts 📈 +44 B (+0.60%) 7.13 kB → 7.17 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +6 B (+0.55%) 1.07 kB → 1.08 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/category-template-context.ts 📈 +38 B (+0.22%) 17.07 kB → 17.11 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +9 B (+0.11%) 7.74 kB → 7.75 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts 📈 +6 B (+0.03%) 22.12 kB → 22.12 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/actions.ts 📉 -8 B (-0.07%) 11.27 kB → 11.27 kB
View detailed bundle breakdown

Added

Asset File Size % Changed
kcab.worker.CrMC0k1i.js 0 B → 4.83 MB (+4.83 MB) -

Removed

Asset File Size % Changed
kcab.worker.Dmj0rSrb.js 4.83 MB → 0 B (-4.83 MB) -100%

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged
No assets were unchanged


api

Total

Files count Total bundle size % Changed
4 4.06 MB → 4.06 MB (+3.19 kB) +0.08%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts 📈 +347 B (+13.14%) 2.58 kB → 2.92 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts 📈 +1.18 kB (+4.90%) 24.12 kB → 25.3 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts 📈 +268 B (+4.51%) 5.81 kB → 6.07 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +202 B (+3.15%) 6.26 kB → 6.45 kB
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/transaction-rules.ts 📈 +531 B (+2.72%) 19.04 kB → 19.55 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts 📈 +237 B (+2.52%) 9.17 kB → 9.41 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts 📈 +195 B (+0.89%) 21.31 kB → 21.5 kB
home/runner/work/actual/actual/packages/loot-core/src/server/api.ts 📈 +183 B (+0.81%) 21.96 kB → 22.14 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/schedule-template.ts 📈 +43 B (+0.60%) 6.99 kB → 7.03 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/customFunctions.ts 📈 +6 B (+0.56%) 1.05 kB → 1.06 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/category-template-context.ts 📈 +38 B (+0.23%) 16.23 kB → 16.27 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +9 B (+0.12%) 7.31 kB → 7.32 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts 📈 +6 B (+0.03%) 21.75 kB → 21.76 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/actions.ts 📉 -8 B (-0.07%) 10.97 kB → 10.97 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
index.js 3.84 MB → 3.84 MB (+3.19 kB) +0.08%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
from-Bl-Hslp4.js 167.73 kB 0%
multipart-parser-BnDysoMr.js 8.1 kB 0%
src-iMkUmuwR.js 43.64 kB 0%

cli

Total

Files count Total bundle size % Changed
1 7.88 MB 0%
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger
No assets were bigger

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
cli.js 7.88 MB 0%

@actual-github-bot actual-github-bot bot changed the title fix(currency): honor per-currency decimal places across app and bank sync [WIP] fix(currency): honor per-currency decimal places across app and bank sync Feb 12, 2026
@netlify
Copy link
Copy Markdown

netlify bot commented Feb 12, 2026

Deploy Preview for actualbudget ready!

Name Link
🔨 Latest commit a74fe75
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget/deploys/69bd9f37390b2f0008278cc3
😎 Deploy Preview https://deploy-preview-6954.demo.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@github-actions
Copy link
Copy Markdown
Contributor

👋 Hello contributor!

We would love to review your PR! Before we can do that, please make sure:

  • ✅ All CI checks pass
  • ✅ The PR is moved from draft to open (if applicable)
  • ✅ The "[WIP]" prefix is removed from the PR title
  • ✅ All CodeRabbit code review comments are resolved (if you disagree with anything - reply to the bot with your reasoning so we can read through it). The bot will eventually approve the PR.

We do this to reduce the TOIL the core contributor team has to go through for each PR and to allow for speedy reviews and merges.

For more information, please see our Contributing Guide.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds data-driven Playwright e2e tests for currency formatting/precision, a currency-precision helper and Settings page helpers to toggle/select currency, and updates the VRT workflow to reduce noisy PNG snapshot commits.

Changes

Cohort / File(s) Summary
Accounts tests
packages/desktop-client/e2e/accounts.test.ts
Replaced single currency-balance test with a parameterized Currency Precision suite: sets default currency, creates accounts, asserts formatted balances/transactions, verifies close-account modal flows, and captures theme screenshots.
Budget tests
packages/desktop-client/e2e/budget.test.ts
Added Currency Precision describe block that sets default currency per dataset, navigates to /budget, waits for load/networkidle and UI visibility, and captures theme screenshots.
Currency precision helper
packages/desktop-client/e2e/currency-precision.ts
New module exporting CurrencyPrecisionDatum type, currencyPrecisionTestData (datasets for default, JPY, USD, KWD), and setDefaultCurrency(page, navigation, currencyCode) to enable/disable experimental currency support and select currency.
Settings page model
packages/desktop-client/e2e/page-models/settings-page.ts
Added getExperimentalFeatureCheckbox() (private); enableExperimentalFeature() now awaits checked state; added disableExperimentalFeature() and selectCurrency() to robustly toggle/select experimental currency options.
VRT workflow
.github/workflows/vrt-update-generate.yml
Enhanced VRT workflow to delete old snapshots, stage only e2e snapshot dirs, unstage non-PNG cached changes, and discard PNGs with ≤±2KB byte-delta to avoid noisy snapshot commits.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Playwright Test
    participant Nav as Navigation (page-model)
    participant Settings as Settings Page
    participant App as App UI (Accounts/Budget)

    Test->>Nav: goToSettingsPage()
    Nav->>Settings: open Settings
    Test->>Settings: setDefaultCurrency(code)
    Settings-->>Test: confirm currency selected / experimental toggled
    Test->>App: navigate to target page (accounts or budget)
    App-->>Test: render with selected currency
    Test->>App: create account / open modal / assert formatted balances
    App-->>Test: return displayed values (expectedDisplay)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through settings, toggled with care,
Counting decimals that float in the air.
From Default to KWD, JPY, USD too,
I checked each balance, precise and true. ✨

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Honor per-currency decimal places across app' is concise, clear, and accurately summarizes the main objective of the PR—fixing the assumption that all currencies use two decimal places and making amounts respect each currency's decimalPlaces.
Linked Issues check ✅ Passed The PR fully addresses the requirements from linked issues #325, #3255, and #5748 by implementing support for zero-decimal currencies (CLP, JPY, VND), three-decimal currencies (KWD, BHD, IQD, JOD, LYD, OMR, TND), and correct currency metadata/symbols across account creation, transaction flows, and budget UI.
Out of Scope Changes check ✅ Passed All code changes align with the stated PR scope (desktop-client and loot-core currency precision); sync-server adapter work was intentionally removed from scope per architectural review, and VRT workflow updates support the E2E testing infrastructure.
Description check ✅ Passed The PR description comprehensively explains the changes: fixing non-2-decimal currency handling across desktop-client and loot-core, correcting VND metadata, detailing test additions, and noting database migration implications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/sync-server/src/app-pluggyai/app-pluggyai.js (1)

132-140: ⚠️ Potential issue | 🟡 Minor

Minor inconsistency: rounding uses fallback currency but transactionAmount.currency does not.

Line 134 falls back to account.currencyCode when trans.currencyCode is falsy, but line 139 stores currency: trans.currencyCode without the same fallback. If trans.currencyCode is undefined, the amount is rounded using the account's currency precision but tagged with an undefined currency.

Proposed fix
+        const effectiveCurrency = trans.currencyCode || account.currencyCode;
         amountInCurrency = roundToCurrencyDecimals(
           amountInCurrency,
-          trans.currencyCode || account.currencyCode,
+          effectiveCurrency,
         );

         newTrans.transactionAmount = {
           amount: amountInCurrency,
-          currency: trans.currencyCode,
+          currency: effectiveCurrency,
         };
🤖 Fix all issues with AI agents
In `@packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js`:
- Line 1: Rename this adapter file from .js to .ts and convert its module shape
to TypeScript: change any CommonJS exports to ES module syntax (use export or
export default), add explicit types for all function parameters and return
values (e.g., annotate the adapter entry function, any helpers, and imported
values like amountToInteger usage), import any types you need from surrounding
packages (e.g., types for transactions, bank records, or amount
representations), and fix any implicit any or dynamic property access by
declaring appropriate interfaces or type aliases; finally run type-checking and
adjust any runtime-specific code (global/require usage) to be
TypeScript-compatible.

In `@packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js`:
- Around line 36-50: The reduce call currently passes currency code strings into
amountToInteger (in the sortedTransactions.reduce and the initial amount for
currentBalance.balanceAmount), causing NaN; fix by resolving the currency to its
decimalPlaces via getCurrency(...) and pass that number as the second arg to
amountToInteger (e.g., const dp =
getCurrency(trans.transactionAmount.currency).decimalPlaces and use
amountToInteger(trans.transactionAmount.amount, dp)), and do the same for
currentBalance.balanceAmount before the reduce; ensure getCurrency is
imported/available in this module and use the same symbol names
(amountToInteger, sortedTransactions.reduce, currentBalance.balanceAmount) so
both call sites pass a numeric decimalPlaces value instead of the currency
string.

In `@packages/sync-server/src/app-gocardless/banks/nbg_ethngraaxxx.js`:
- Around line 47-61: The reduce currently passes a currency code string into
amountToInteger, causing NaN; change calls so you resolve the currency to its
decimalPlaces first (e.g., use
getCurrency(trans.transactionAmount.currency).decimalPlaces and
getCurrency(currentBalance.balanceAmount.currency).decimalPlaces) and pass that
number as the second argument to amountToInteger for both the per-transaction
conversion and the initial balance in the reduce; update every occurrence in the
GoCardless bank files (e.g., nbg_ethngraaxxx.js) that references amountToInteger
with transactionAmount.currency or currentBalance.balanceAmount.currency.
🧹 Nitpick comments (1)
packages/sync-server/src/app-simplefin/app-simplefin.js (1)

232-235: Minor inconsistency in currency fallback: '' vs 'USD'.

Line 182 falls back to getCurrency(account.currency || '') (resolving to the "None" currency with 2 decimal places), while line 234 falls back to 'USD'. Both happen to yield 2 decimal places, but the intent differs. Consider using a consistent fallback (e.g., 'USD' in both places, or extracting the resolved currency once).

Comment thread packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/nbg_ethngraaxxx.js Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 10

🤖 Fix all issues with AI agents
In `@packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js`:
- Around line 42-56: The code is passing a currency code string into
amountToInteger instead of the numeric decimalPlaces; find the calls to
amountToInteger in this module (e.g., where oldestKnownBalance and balance are
computed using oldestTransaction.balanceAfterTransaction.balanceAmount.currency
and balance.balanceAmount.currency) and replace the currency string with
getCurrency(<currencyCode>).decimalPlaces (e.g., const currency =
getCurrency(...); then pass currency.decimalPlaces to amountToInteger) so
Math.pow receives a number and balance calculations work correctly.

In `@packages/sync-server/src/app-gocardless/banks/danskebank_privat.js`:
- Around line 37-51: The reduction is passing a currency code string into
amountToInteger where a decimalPlaces number is required, causing NaN; update
the calls inside the reducer and the initial value to use
getCurrency(...).decimalPlaces instead of the raw currency string — i.e., for
trans.transactionAmount.currency and currentBalance.balanceAmount.currency call
getCurrency(currency).decimalPlaces and pass that number into amountToInteger
(affecting the sortedTransactions reducer and the initial amountToInteger call).

In `@packages/sync-server/src/app-gocardless/banks/entercard_swednokk.js`:
- Around line 35-46: The bug is passing a currency code string into
amountToInteger's second parameter (decimalPlaces); update the code to import
and use getCurrency to derive decimal places and pass that number instead.
Specifically, where amountToInteger(...) is called with
trans.transactionAmount.currency or balances[0]?.balanceAmount?.currency as the
second arg, replace that argument with getCurrency(<currencyCode>).decimalPlaces
(e.g., getCurrency(trans.transactionAmount.currency).decimalPlaces and
getCurrency(balances[0]?.balanceAmount?.currency).decimalPlaces) and add the
import for getCurrency from 'loot-core/shared/currencies'; keep amountToInteger
usage otherwise unchanged.

In `@packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js`:
- Around line 43-57: The reduce currently calls amountToInteger(...,
trans.transactionAmount.currency) and amountToInteger(...,
currentBalance.balanceAmount.currency) passing currency codes (strings) instead
of numeric decimal places; update those calls to pass
getCurrency(trans.transactionAmount.currency).decimalPlaces and
getCurrency(currentBalance.balanceAmount.currency).decimalPlaces respectively so
amountToInteger receives a number; keep the rest of the reduce logic and use the
existing getCurrency helper like other integrations.

In `@packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js`:
- Around line 31-45: The bug is that amountToInteger is being called with a
currency string (e.g.,
oldestTransaction.balanceAfterTransaction.balanceAmount.currency or
balance.currency) where it expects decimalPlaces (a number), causing NaN; fix by
resolving the currency to its decimal places before calling amountToInteger
(e.g., add or reuse a helper like
currencyToDecimalPlaces/getCurrencyDecimalPlaces and pass its numeric result
into amountToInteger for both calls that compute
oldestKnownBalance/oldestTransactionAmount and the interimBooked balance),
ensuring all references to amountToInteger(...) use the decimalPlaces number
rather than the currency string.

In `@packages/sync-server/src/app-gocardless/banks/integration-bank.js`:
- Around line 89-103: The reduce that computes the balance uses a broken import
and passes a currency string to amountToInteger; replace the broken import of
amountToInteger with the correct utility from loot-core/shared/util (or the
module that currently exports amountToInteger) and change callers to resolve
decimal places via getCurrency(currencyCode). Specifically, in the file
referencing amountToInteger, import getCurrency and the correct amountToInteger
export, then in the reduce over sortedTransactions (and the initial
currentBalance call) call amountToInteger(trans.transactionAmount.amount,
getCurrency(trans.transactionAmount.currency).decimalPlaces) and
amountToInteger(currentBalance?.balanceAmount?.amount || 0,
getCurrency(currentBalance?.balanceAmount?.currency).decimalPlaces) so the
second arg is a number not a string.

In `@packages/sync-server/src/app-gocardless/banks/norwegian_xx_norwnok1.js`:
- Line 1: Rename the adapter file norwegian_xx_norwnok1.js to
norwegian_xx_norwnok1.ts and convert its exports and functions to TypeScript:
change any CommonJS exports to ES module exports (export default / named
exports), add explicit type annotations for function parameters and return
values (e.g., transaction/amount types used by the adapter), and import
amountToInteger with proper types (import { amountToInteger } from
'loot-core/shared/util';). Ensure any JSON or external data parsed by the
adapter is typed (use interfaces for parsed records) and fix any TypeScript
compile errors (missing types, implicit any) so the module builds cleanly under
the repo TypeScript rules.

In `@packages/sync-server/src/app-gocardless/banks/seb_kort_bank_ab.js`:
- Around line 71-89: The three calls to amountToInteger are passing a currency
string where a decimalPlaces number is expected (in the reduce over
sortedTransactions and the initial accumulator using currentBalance and
nonInvoiced), causing NaN; update each call to pass
getCurrency(<currency>).decimalPlaces instead of the raw currency
string—specifically change the amountToInteger invocations that reference
trans.transactionAmount.currency, currentBalance.balanceAmount.currency, and
nonInvoiced.balanceAmount.currency to use getCurrency(...).decimalPlaces so
amountToInteger receives the numeric decimalPlaces parameter.

In `@packages/sync-server/src/app-gocardless/banks/seb_privat.js`:
- Around line 25-39: The reduction currently calls amountToInteger(...,
trans.transactionAmount.currency) and amountToInteger(...,
currentBalance.balanceAmount.currency) passing currency strings (causing NaN);
update both calls to pass the numeric decimalPlaces from the currency object
instead, e.g. call getCurrency(trans.transactionAmount.currency).decimalPlaces
and getCurrency(currentBalance.balanceAmount.currency).decimalPlaces so
amountToInteger receives a number; adjust the two locations inside the
sortedTransactions.reduce and the initial accumulator accordingly.

In `@packages/sync-server/src/app-simplefin/app-simplefin.js`:
- Around line 180-183: The code uses inconsistent fallbacks for missing
account.currency (getCurrency(account.currency || '') in the startingBalance
calculation vs getCurrency(account.currency || 'USD') elsewhere); update both
places that call getCurrency with account.currency to use the same explicit
fallback (e.g., 'USD') so decimalPlaces are computed consistently—search for
calls around startingBalance and the later balance parsing (the
amountToInteger(parseFloat(account.balance), getCurrency(...).decimalPlaces)
patterns) and replace the '' fallback with 'USD' (or a single chosen constant)
across both occurrences.
🧹 Nitpick comments (2)
upcoming-release-notes/6954.md (1)

6-6: Make the release note a complete, user-facing sentence.

This is concise but reads like a fragment. Consider a short sentence like “Fixes amounts for currencies with non‑standard decimal places across the app.”
As per coding guidelines, keep upcoming-release-notes entries concise and non-technical.

packages/loot-core/src/shared/currencies.ts (1)

64-64: Add support for three-decimal currencies (KWD, BHD) to complete PR objectives.

The VND change to decimalPlaces: 0 is safe—sync adapters already properly pass currency-specific decimal places via getCurrencyDecimalPlaces(). However, the PR objectives mention adding three-decimal currency support (KWD, BHD, etc.), and these entries are missing from currencies.ts. Add them to fully deliver on the stated goals.

Comment thread packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/danskebank_privat.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/integration-bank.js
Comment thread packages/sync-server/src/app-gocardless/banks/norwegian_xx_norwnok1.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/seb_kort_bank_ab.js
Comment thread packages/sync-server/src/app-simplefin/app-simplefin.js Outdated
@netlify
Copy link
Copy Markdown

netlify bot commented Feb 13, 2026

Deploy Preview for actualbudget-website ready!

Name Link
🔨 Latest commit d0fa236
🔍 Latest deploy log https://app.netlify.com/projects/actualbudget-website/deploys/69bd9b7fd23b460008840214
😎 Deploy Preview https://deploy-preview-6954.www.actualbudget.org
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🤖 Fix all issues with AI agents
In `@packages/sync-server/src/app-gocardless/bank-factory.js`:
- Around line 13-18: The filename filter in
packages/sync-server/src/app-gocardless/bank-factory.js incorrectly accepts
TypeScript files by checking filename.endsWith('.ts'); remove the .ts branch
from the .filter callback so it only accepts files ending with '.js' (and still
requires '_' in the name), ensuring runtime only loads compiled JavaScript
modules; update the filter expression that currently checks
filename.includes('_') && (filename.endsWith('.js') || (filename.endsWith('.ts')
&& !filename.endsWith('.d.ts'))) to only allow filename.endsWith('.js')
alongside the underscore check.

In `@packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.ts`:
- Around line 53-57: sortTransactions currently assumes every transaction has
valueDateTime, which can produce NaN and break sorting; update sortTransactions
to guard against missing valueDateTime by using a fallback date (e.g.,
bookingDate or epoch) when valueDateTime is falsy, convert the chosen date to a
timestamp safely, and use that timestamp for comparisons in the comparator so
transactions without valueDateTime sort deterministically; locate the logic in
the sortTransactions method in abnamro_abnanl2a.ts and apply the fallback there.

In `@packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js`:
- Around line 46-48: The direct access to .balanceAmount after
balances.find(...) can throw if no 'interimBooked' entry exists; change the
inline extraction to first store the found item (e.g., const interim =
balances.find(b => b.balanceType === 'interimBooked')), then safely read its
amount using optional chaining or a fallback (e.g., const balance =
interim?.balanceAmount ?? null or 0) to avoid a TypeError when interim is
undefined.

In `@packages/sync-server/src/app-gocardless/banks/norwegian_xx_norwnok1.js`:
- Around line 71-85: The reducer mixes integer amounts converted with differing
decimalPlaces (transaction currency vs balance currency), producing incorrect
arithmetic; change it so all conversions use the account/balance currency's
decimalPlaces: compute balanceCurrencyDecimals once from
currentBalance.balanceAmount.currency (fallback if missing) and call
amountToInteger(..., balanceCurrencyDecimals) for the initial total and for
every trans in sortedTransactions (instead of passing
getCurrency(trans.transactionAmount.currency).decimalPlaces); keep using
sortedTransactions.reduce and amountToInteger but normalize every value to the
balance currency scale.
- Around line 75-78: The amount passed to amountToInteger is a string from the
GoCardless API; update the call site so trans.transactionAmount.amount is
explicitly converted to a number (e.g., via Number()) before passing to
amountToInteger, keeping the getCurrency(trans.transactionAmount.currency ||
'').decimalPlaces usage unchanged to ensure correct decimalPlaces lookup.

In `@packages/sync-server/src/app-gocardless/banks/sandboxfinance_sfin0000.js`:
- Around line 25-39: The reduce and initial balance calls pass GoCardless string
amounts into amountToInteger (which expects a numeric Amount), so convert those
string amount values to numbers before calling amountToInteger; update the
reducer to call amountToInteger(Number(trans.transactionAmount.amount),
getCurrency(...).decimalPlaces) and the initial value to
amountToInteger(Number(currentBalance.balanceAmount.amount),
getCurrency(...).decimalPlaces), ensuring you use Number(...) or parseFloat(...)
to match the pattern used in abnamro_abnanl2a.ts and respect the
amountToInteger(amount: Amount, decimalPlaces) contract.

In `@packages/sync-server/src/app-pluggyai/app-pluggyai.js`:
- Around line 131-140: The code uses effectiveCurrency (trans.currencyCode ||
account.currencyCode) for both rounding and labeling even when amountInCurrency
comes from trans.amountInAccountCurrency, causing mismatched currency/precision;
change the logic in the block that computes amountInCurrency/amount rounding and
newTrans.transactionAmount so that the currency used for roundToCurrencyDecimals
and for the resulting transactionAmount.currency is tied to the actual amount
source: if trans.amountInAccountCurrency is non-null/defined, set the
roundingCurrency and label to account.currencyCode and round
trans.amountInAccountCurrency, otherwise use trans.amount and use
trans.currencyCode (falling back to account.currencyCode as currently done);
update variables effectiveCurrency/amountInCurrency accordingly and ensure
newTrans.transactionAmount.amount matches the chosen amount value and currency.
🧹 Nitpick comments (1)
packages/sync-server/src/app-gocardless/banks/integration-bank.js (1)

90-101: trans.transactionAmount.amount is a string from the GoCardless API — implicit coercion is fragile.

The GoCardless API returns transactionAmount.amount as a string (e.g., "123.45"), and amountToInteger in loot-core/shared/util is typed to accept a numeric Amount. JavaScript's * operator coerces the string to a number at runtime, so this won't break, but it silently depends on implicit coercion and would fail TypeScript type-checking if this file is ever migrated.

Consider wrapping with Number(...) for clarity:

Suggested improvement
       return (
         total -
         amountToInteger(
-            trans.transactionAmount.amount,
+            Number(trans.transactionAmount.amount),
             getCurrency(trans.transactionAmount.currency || '').decimalPlaces,
         )
       );
     },
     amountToInteger(
-        currentBalance?.balanceAmount?.amount || 0,
+        Number(currentBalance?.balanceAmount?.amount || 0),
         getCurrency(currentBalance?.balanceAmount?.currency || '').decimalPlaces,
     ),

Comment thread packages/sync-server/src/app-gocardless/bank-factory.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js
Comment thread packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/norwegian_xx_norwnok1.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/norwegian_xx_norwnok1.js Outdated
Comment thread packages/sync-server/src/app-pluggyai/app-pluggyai.js Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 11

🤖 Fix all issues with AI agents
In `@packages/loot-core/src/server/accounts/sync.ts`:
- Around line 448-451: trans.amount can be a string (e.g. GoCardless
transactionAmount.amount) but is passed into amountToInteger which expects a
numeric Amount; update normalizeBankSyncTransactions so trans.amount is
explicitly coerced to a Number when assigned from trans.transactionAmount.amount
and also ensure the call site that uses trans.amount (the amountToInteger(...)
invocation with getCurrencyDecimalPlaces) wraps the value with Number(...) or
parseFloat(...) and handles NaN (e.g., treat as 0 or throw an explicit error).
Target the assignment where trans.amount is set from transactionAmount.amount
and the call using amountToInteger to ensure type-safe numeric conversion.

In `@packages/loot-core/src/shared/currencies.ts`:
- Line 64: The VND mapping change (code 'VND' in currencies.ts) from
decimalPlaces:2 to decimalPlaces:0 will re-interpret existing stored integer
amounts and cause a 100x inflation, so either revert to decimalPlaces:2 until a
migration exists or implement a data migration/versioned conversion: detect rows
where currency == 'VND' and convert stored integer amounts by dividing by 100
(or otherwise rescaling values to match new zero-decimal semantics), record a
schema/data version flag, update any import/export/seed logic and unit tests
that rely on VND handling, and only then change the currencies.ts entry to
decimalPlaces:0.

In `@packages/loot-core/src/shared/util.ts`:
- Around line 458-483: The divisible-by-divisor branch of
integerToCurrencyWithDecimal currently always forces decimalPlaces and ignores
the configured hideFraction setting; update the second getNumberFormat call
inside integerToCurrencyWithDecimal to pass hideFraction:
numberFormatConfig.hideFraction (or otherwise derive hideFraction from your
numberFormatConfig) so that when there are no fractional digits the formatter
respects the hideFraction setting; keep the first branch using hideFraction:
false for the case where fractional digits exist.

In `@packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js`:
- Around line 62-75: The code converts
oldestTransaction.balanceAfterTransaction.balanceAmount and
oldestTransaction.transactionAmount using potentially different currency scales
(decimalPlaces), causing mixed-scale subtraction; update the conversion so both
amountToInteger calls use the balance currency's decimalPlaces (retrieve once
from oldestTransaction.balanceAfterTransaction.balanceAmount.currency via
getCurrency) and use that same decimalPlaces for oldestKnownBalance and
oldestTransactionAmount to ensure both integers share the same scale (refer to
amountToInteger, getCurrency, oldestKnownBalance, oldestTransactionAmount).

In `@packages/sync-server/src/app-gocardless/banks/entercard_swednokk.js`:
- Around line 36-47: Convert string amounts to numbers and use a single balance
currency scale when computing integer amounts: ensure calls to amountToInteger
wrap trans.transactionAmount.amount and balances[0]?.balanceAmount?.amount with
Number(...), and compute a single balanceCurrencyDecimals once by calling
getCurrency(...) on balances[0]?.balanceAmount?.currency (or fallback) then pass
that balanceCurrencyDecimals into every amountToInteger invocation (instead of
using each transaction's own getCurrency(...).decimalPlaces) so all integers
share the same scale.

In `@packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js`:
- Around line 44-58: The reduce block subtracts transaction amounts but assumes
string-to-number conversion and that currentBalance exists; update the logic in
the sortedTransactions.reduce call to wrap amount strings with Number(...)
before passing into amountToInteger (e.g., trans.transactionAmount.amount and
currentBalance.balanceAmount.amount) and defensively handle a potentially
undefined currentBalance (from the prior find()) by defaulting the starting
balance to 0 (or "0") so amountToInteger always receives a valid amount; keep
using getCurrency(...).decimalPlaces for precision.

In `@packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js`:
- Around line 32-43: oldestKnownBalance and oldestTransactionAmount are passing
GoCardless string amounts directly into amountToInteger; convert the string
amounts to numbers (use Number(...) with a fallback like 0) before calling
amountToInteger so getCurrency(...).decimalPlaces stays correct. Update the
calls that use oldestTransaction.balanceAfterTransaction.balanceAmount.amount
and oldestTransaction.transactionAmount.amount to wrap them in Number(... || 0)
while keeping the existing getCurrency(...) usage.

In `@packages/sync-server/src/app-gocardless/banks/sandboxfinance_sfin0000.js`:
- Around line 25-39: The reduce currently assumes currentBalance (result of the
earlier find stored in variable currentBalance) is always present and will throw
if undefined; guard against that by checking for undefined before using
currentBalance.balanceAmount (or provide a default zero balance object), e.g.
compute a safe starting value for the reduce by using optional chaining or a
fallback amount derived from
amountToInteger(Number(currentBalance?.balanceAmount?.amount || 0),
getCurrency(currentBalance?.balanceAmount?.currency || '').decimalPlaces) so the
call sites in sortedTransactions.reduce, amountToInteger, and getCurrency are
safe when currentBalance is missing.

In `@packages/sync-server/src/app-gocardless/banks/seb_privat.js`:
- Around line 26-40: The reduce block is passing string amounts into
amountToInteger and can crash when currentBalance is undefined; convert
transactionAmount.amount and currentBalance.balanceAmount.amount via Number(...)
before calling amountToInteger (e.g., wrap trans.transactionAmount.amount and
currentBalance.balanceAmount.amount with Number) and guard against missing
currentBalance by defaulting the starting amount to 0 (or returning 0) when
currentBalance is falsy; update references in this file to use Number(...) and
check currentBalance before accessing .balanceAmount to prevent runtime errors
in the reduce calculation.

In `@packages/sync-server/src/app-gocardless/banks/spk_karlsruhe_karsde66.js`:
- Around line 58-72: The reduce callback in sortedTransactions.reduce subtracts
transaction amounts and initializes total using currentBalance without
converting string amounts to numbers and without guarding currentBalance; wrap
trans.transactionAmount.amount and currentBalance.balanceAmount.amount with
Number(...) before passing to amountToInteger, and add a guard so if
currentBalance is undefined use 0 (e.g. default to 0 for the initializer) —
update usages around sortedTransactions.reduce, amountToInteger,
trans.transactionAmount.amount, currentBalance.balanceAmount.amount, and
getCurrency to reflect these changes.

In `@packages/sync-server/src/app-gocardless/banks/ssk_munchen.js`:
- Around line 50-64: The reducer currently passes string amounts to
amountToInteger (via trans.transactionAmount.amount and
currentBalance.balanceAmount.amount) and doesn't guard currentBalance; wrap both
trans.transactionAmount.amount and currentBalance.balanceAmount.amount with
Number(...) before calling amountToInteger, and add a null/undefined guard for
currentBalance (or default to "0") so sortedTransactions.reduce starts from a
numeric initial balance; update references in the sortedTransactions.reduce
block and where currentBalance is read so getCurrency/currentBalance usage
remains safe.
🧹 Nitpick comments (4)
packages/sync-server/package.json (1)

18-21: Published package ships duplicate build artifacts.

After normalize-build-layout copies files from build/sync-server/ into build/bin/, build/src/, and build/app.js, the original build/sync-server/ tree is never removed. Combined with "files": ["build"], the published package will contain both the nested and flattened layouts — roughly doubling the build artifact size.

Similarly, copy-static-assets duplicates SQL files into both build/src/sql and build/sync-server/src/sql, which can silently diverge if one path is updated but not the other.

Consider adding rm -rf build/sync-server at the end of normalize-build-layout, and then only copying SQL assets to build/src/sql.

packages/sync-server/src/app-gocardless/banks/seb_kort_bank_ab.js (1)

1-2: Convert this sync-server module to TypeScript.
This file lives under packages/ and remains JS; the repo guideline calls for TS. Consider a follow-up conversion if it’s not in scope here.

As per coding guidelines: **/{packages,src}/**/*.{js,jsx}: Use TypeScript for all code.

packages/sync-server/src/app-simplefin/app-simplefin.js (1)

1-7: Convert this sync-server module to TypeScript.
This file lives under packages/ and remains JS; the repo guideline calls for TS. Consider a follow-up conversion if it’s not in scope here.

As per coding guidelines: **/{packages,src}/**/*.{js,jsx}: Use TypeScript for all code.

packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx (1)

451-477: Double conversion of transaction.amount — correct but worth noting.

The amount is converted from integer → float (in serializeTransaction) and then back to integer (line 457) just to pass to AmountInput. The round-trip is mathematically sound with matching decimalPlaces, but it's an unnecessary hop compared to passing the original integer directly. Not blocking — just a minor observation.

Comment thread packages/loot-core/src/server/accounts/sync.ts Outdated
Comment thread packages/loot-core/src/shared/currencies.ts
Comment thread packages/loot-core/src/shared/util.ts
Comment thread packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js
Comment thread packages/sync-server/src/app-gocardless/banks/entercard_swednokk.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/ing_pl_ingbplpw.js
Comment thread packages/sync-server/src/app-gocardless/banks/sandboxfinance_sfin0000.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/seb_privat.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/spk_karlsruhe_karsde66.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/ssk_munchen.js Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/desktop-client/src/components/transactions/TransactionsTable.tsx (1)

1616-1676: ⚠️ Potential issue | 🟠 Major

Debit/credit cell formatters use amountToCurrency without currency-specific decimal place handling.

The debit and credit InputCell formatters (lines 1624–1627, 1655–1658) call amountToCurrency(...) which lacks a decimalPlaces parameter, causing it to default to 2 decimal places. This contradicts the PR's goal of eliminating the 2-decimal assumption and will reformat user input incorrectly for zero- and three-decimal currencies (e.g., 1001.00 for JPY).

The component already has access to decimalPlaces from useFormat() (line 936) and correctly passes it to integerToCurrency elsewhere (line 1685). The amountToCurrency function should either accept a decimalPlaces parameter like integerToCurrency does, or the formatters should use an alternative that respects currency decimal places.

🤖 Fix all issues with AI agents
In `@packages/loot-core/src/server/accounts/sync.ts`:
- Around line 409-420: The falsy check if (!trans.amount) incorrectly treats a
valid zero amount as missing; change it to a nullish check (trans.amount ==
null) so only null/undefined are replaced from trans.transactionAmount?.amount,
then keep coercion via Number(trans.amount) into normalizedAmount and retain the
NaN guard and the mapping lookup (mappings.get(normalizedAmount <= 0 ? 'payment'
: 'deposit')) unchanged.
- Around line 954-975: The initial-sync balance calculations use
transactions.reduce calling amountToInteger(trans.transactionAmount.amount,
getCurrencyDecimalPlaces(...)) on raw responses where
trans.transactionAmount.amount can be a string; update both reduce usages (the
SimpleFIN branch computing previousBalance and the pluggyai branch computing
previousBalance) to explicitly coerce the amount to a Number (wrap
trans.transactionAmount.amount with Number(...)) before passing to
amountToInteger so behavior matches normalizeBankSyncTransactions.
🧹 Nitpick comments (1)
packages/sync-server/src/app-pluggyai/app-pluggyai.js (1)

17-21: roundToCurrencyDecimals duplicates logic already available in the shared utility layer.

This helper is equivalent to integerToAmount(amountToInteger(amount, dp), dp). Consider reusing those functions to avoid divergence:

Suggested refactor
-function roundToCurrencyDecimals(amount, currencyCode) {
-  const decimalPlaces = getCurrency(currencyCode || '').decimalPlaces;
-  const multiplier = Math.pow(10, decimalPlaces);
-  return Math.round(amount * multiplier) / multiplier;
-}
+function roundToCurrencyDecimals(amount, currencyCode) {
+  const decimalPlaces = getCurrency(currencyCode || '').decimalPlaces;
+  return integerToAmount(amountToInteger(amount, decimalPlaces), decimalPlaces);
+}

This requires importing integerToAmount from loot-core/shared/util alongside amountToInteger.

Comment thread packages/loot-core/src/server/accounts/sync.ts Outdated
Comment thread packages/loot-core/src/server/accounts/sync.ts
@StephenBrown2
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx (1)

280-300: ⚠️ Potential issue | 🔴 Critical

Remove undefined as the second argument; the formatter parameter has a default and passing undefined explicitly will cause a runtime error.

The integerToCurrency function signature is:

export function integerToCurrency(
  integerAmount: IntegerAmount,
  formatter = getNumberFormat().formatter,
  decimalPlaces: number = 2,
)

While the second parameter has a default value, passing undefined explicitly does not trigger it—the default only applies when the argument is omitted. The function then calls formatter.format(amount) on line 455, which fails at runtime if formatter is undefined.

Either omit the second argument entirely (integerToCurrency(value, decimalPlaces)) or provide the actual formatter value.

packages/desktop-client/src/components/mobile/transactions/FocusableAmountInput.tsx (1)

85-93: ⚠️ Potential issue | 🟡 Minor

onTotalAmountUpdate in TransactionEdit.tsx does not apply amountToInteger — conversion happens downstream in deserializeTransaction.

The callback receives a decimal amount from FocusableAmountInput and passes it directly to onUpdateInner without calling amountToInteger. The actual conversion occurs later when onUpdate calls deserializeTransaction(serializedTransaction, null, dateFormat, decimalPlaces), which applies amountToInteger(amount || 0, decimalPlaces) at that point.

This differs from TrackingBudgetMenuModal and EnvelopeBudgetMenuModal, where _onUpdateBudget applies amountToInteger immediately within the callback before passing to the parent. While the TransactionEdit approach works because the conversion happens before persistence, the inconsistent pattern across consumers could introduce bugs if the downstream conversion step is ever missed or bypassed.

packages/sync-server/src/app-gocardless/banks/berliner_sparkasse_beladebexxx.js (1)

45-52: ⚠️ Potential issue | 🟡 Minor

Stale JSDoc references SANDBOXFINANCE_SFIN0000 instead of BERLINER_SPARKASSE_BELADEBEXXX.

The comment on line 46 mentions "SANDBOXFINANCE_SFIN0000" but this adapter is for BERLINER_SPARKASSE_BELADEBEXXX. This is a pre-existing copy-paste issue but worth fixing while touching this code.

Proposed fix
   /**
-   *  For SANDBOXFINANCE_SFIN0000 we don't know what balance was
+   *  For BERLINER_SPARKASSE_BELADEBEXXX we don't know what balance was
    *  after each transaction so we have to calculate it by getting
    *  current balance from the account and subtract all the transactions
🤖 Fix all issues with AI agents
In `@packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js`:
- Around line 51-60: The current branch in the code checks
hasBalanceAfterTransaction on sortedTransactions[0] and then, if the
oldestTransaction (sortedTransactions[sortedTransactions.length - 1]) lacks
balanceAfterTransaction, returns 0; instead remove that early return and let
execution fall through to the interimBooked balance path so partial
balanceAfterTransaction data doesn’t force a zero starting balance. Update the
block around sortedTransactions, hasBalanceAfterTransaction, and
oldestTransaction to skip the return 0 case and allow the later interimBooked
handling (the logic that reads interimBooked on lines ~79-89) to execute when
the oldest transaction has no balanceAfterTransaction.

In `@packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js`:
- Around line 1-2: This file was converted to JavaScript in isolation but must
remain part of the coordinated sync-server TypeScript migration; revert any
isolated type-only changes and add a clear top-of-file comment (e.g.,
"TODO/MIGRATION: Do not convert in isolation — migrate as part of sync-server
package-wide TS effort per AGENTS.md") so reviewers know this file intentionally
remains JS for now, and ensure existing imports (getCurrency, amountToInteger)
are left unchanged and continue to work in the current JS build until the
package-wide migration is performed.

In `@packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js`:
- Around line 1-2: This file is a JavaScript adapter that must be migrated to
TypeScript: rename the file to .ts, update the module to use TypeScript syntax,
and add appropriate type annotations for the adapter's public API and any
variables that consume getCurrency and amountToInteger; ensure imports remain as
`import { getCurrency }` and `import { amountToInteger }` but annotate their
usages (e.g., currency codes as string, amounts as number, and the adapter's
exported handler return type) so the compiler can validate it, update any
default/exported object to use typed interfaces, and run the typechecker/linter
to fix any remaining type errors.
🧹 Nitpick comments (6)
packages/sync-server/src/app-gocardless/banks/integration-bank.js (1)

88-106: Per-transaction currency lookup would be more robust than using the balance currency for all transactions.

currentBalanceDecimals is derived from the balance object's currency and then applied to every transaction's amount. If a transaction's transactionAmount.currency differs from the balance currency (e.g., a foreign-currency posting), the wrong decimalPlaces would be used for scaling, silently producing an incorrect integer.

Consider resolving decimal places per transaction:

♻️ Suggested change
     return sortedTransactions.reduce(
       (total, trans) => {
+        const txDecimals = getCurrency(
+          trans.transactionAmount.currency || '',
+        ).decimalPlaces;
         return (
           total -
           amountToInteger(
             Number(trans.transactionAmount.amount || 0),
-            currentBalanceDecimals,
+            txDecimals,
           )
         );
       },

That said, for single-currency accounts this is a non-issue, and GoCardless typically returns amounts in the account currency. Up to you whether this edge case warrants the change.

packages/sync-server/src/app-gocardless/banks/ssk_munchen.js (1)

38-45: Nit: stale JSDoc comment references the wrong bank.

The comment says "For SANDBOXFINANCE_SFIN0000" but this is the SSK_MUNCHEN integration. This is a pre-existing copy-paste artifact — consider updating it while you're here.

upcoming-release-notes/6954.md (1)

1-6: Consider timing of release notes for WIP PR.

This PR is currently marked as "[WIP]" (Work In Progress). Release notes are typically added when the PR is ready for merge, not during development, since the implementation may still change. Consider adding or updating this file once the PR is finalized.

packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx (1)

235-235: Consider destructuring or extracting decimalPlaces once at a higher level.

useFormat().currency.decimalPlaces is called independently in four components in this tree (Footer, ChildTransactionEdit, TransactionEditInner, TransactionEditUnconnected). Since they all read the same global currency preference, you could pass decimalPlaces as a prop from TransactionEditUnconnected down through the component tree to avoid redundant hook invocations and make the data flow more explicit. That said, the current approach is idiomatic React and works correctly.

Also applies to: 408-408, 587-587, 1325-1325

packages/loot-core/src/shared/util.ts (1)

241-267: appendDecimals re-parses its own output — fragile round-trip.

The function builds a decimal string manually (lines 252–260), then immediately parses it back to a number via currencyToAmount just to re-format it with Intl.NumberFormat. This parse→format round-trip relies on currencyToAmount correctly handling the string that was just constructed, which is fragile if locale separators change or edge-case amounts arise.

That said, this appears to be the existing pattern extended to support decimalPlaces, so it's not a regression. Just worth noting for a future simplification pass.

packages/desktop-client/src/components/transactions/TransactionsTable.tsx (1)

1738-1777: Apply tabular number styling for the split error amount.

This is a standalone financial value; add styles.tnum (or FinancialText) for consistent numeric alignment.

♻️ Suggested tweak
-              <Text style={{ fontWeight: 500 }}>
+              <Text style={{ fontWeight: 500, ...styles.tnum }}>
                 {integerToCurrency(
                   isDeposit ? error.difference : -error.difference,
                   undefined,
                   decimalPlaces,
                 )}
              </Text>

Based on learnings: Applies to packages/desktop-client/src/**/*.{tsx} : Wrap standalone financial numbers with FinancialText or apply styles.tnum directly if wrapping is not possible.

Comment thread packages/sync-server/src/app-gocardless/banks/abnamro_abnanl2a.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js Outdated
Comment thread packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js Outdated
@github-actions

This comment has been minimized.

@MatissJanis
Copy link
Copy Markdown
Member

FYI: the sync-server is currency agnostic and should remain that way. Besides that - it should not import from loot-core. I'm surprised the build doesn't error our there.. something I will need to look into enforcing better.

@coderabbitai please create a ticket - we should not allow loot-core imports in sync-server (workspaces might be misconfigured if this is allowed)

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 18, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Create a GitHub issue about enforcing that sync-server should not import from loot-core

gh issue create \
  --repo actualbudget/actual \
  --title "Enforce architectural boundary: sync-server should not import from loot-core" \
  --body "## Context

As identified in PR `#6954` (https://github.com/actualbudget/actual/pull/6954), the sync-server package is currently able to import from loot-core, which violates the intended architectural boundary.

## Problem

The sync-server is designed to be currency agnostic and independent from loot-core. However:

1. PR `#6954` added \`loot-core\` as a workspace dependency in \`packages/sync-server/package.json\`
2. Multiple sync-server files now import from loot-core (e.g., \`getCurrency\`, \`amountToInteger\`)
3. The build system does not currently prevent or warn about these cross-package imports

## Proposed Solution

Implement build-time enforcement to prevent sync-server from importing from loot-core:

- Add linting rules or build checks to detect and reject loot-core imports in sync-server
- Review workspace configuration to ensure proper isolation
- Consider using tools like dependency-cruiser or eslint-plugin-import to enforce boundaries

## Related

- Reported by: `@MatissJanis`
- Context PR: `#6954`
- Comment: https://github.com/actualbudget/actual/pull/6954" \
  --assignee MatissJanis \
  --label "technical debt"

Length of output: 47


🏁 Script executed:

#!/bin/bash
# Create a GitHub issue about enforcing that sync-server should not import from loot-core
# Retry without label since 'technical debt' doesn't exist

gh issue create \
  --repo actualbudget/actual \
  --title "Enforce architectural boundary: sync-server should not import from loot-core" \
  --body "## Context

As identified in PR `#6954` (https://github.com/actualbudget/actual/pull/6954), the sync-server package is currently able to import from loot-core, which violates the intended architectural boundary.

## Problem

The sync-server is designed to be currency agnostic and independent from loot-core. However:

1. PR `#6954` added \`loot-core\` as a workspace dependency in \`packages/sync-server/package.json\`
2. Multiple sync-server files now import from loot-core (e.g., \`getCurrency\`, \`amountToInteger\`)
3. The build system does not currently prevent or warn about these cross-package imports

## Proposed Solution

Implement build-time enforcement to prevent sync-server from importing from loot-core:

- Add linting rules or build checks to detect and reject loot-core imports in sync-server
- Review workspace configuration to ensure proper isolation
- Consider tools like dependency-cruiser or eslint-plugin-import to enforce package boundaries

## Related

- Reported by: `@MatissJanis`
- Context PR: `#6954`
- Comment: https://github.com/actualbudget/actual/pull/6954" \
  --assignee MatissJanis

Length of output: 50


@MatissJanis, I've created issue #7017 to track enforcing the architectural boundary between sync-server and loot-core. You're right that this is an important constraint—the sync-server should remain currency agnostic and independent from loot-core.

The changes in this PR that added loot-core imports to sync-server (particularly for currency-aware amount conversions) violate this architectural principle and will need to be refactored.


✏️ Learnings added
Learnt from: MatissJanis
URL: https://github.com/actualbudget/actual/pull/6954

Timestamp: 2026-02-18T21:03:47.908Z
Learning: The sync-server package (packages/sync-server) must remain currency agnostic and should never import from loot-core. This is an architectural boundary that must be maintained. Any currency-aware logic should remain in loot-core or the client layers.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js:1-2
Timestamp: 2026-02-18T20:28:29.023Z
Learning: In the actualbudget/actual repository, JavaScript files under packages/sync-server/src/app-gocardless/banks/ should not be converted to TypeScript in code reviews. These bank integration files are intentionally kept as JS and will be migrated to TypeScript in a separate coordinated effort.

Learnt from: tlesicka
Repo: actualbudget/actual PR: 3689
File: packages/loot-core/src/server/backups.web.ts:203-207
Timestamp: 2024-10-24T05:09:44.115Z
Learning: In `packages/loot-core/src/server/backups.web.ts`, developers prefer to keep the error handling for cloud storage uploads inline rather than extracting it into a separate function. Avoid suggesting this refactoring in future reviews.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js:1-2
Timestamp: 2026-02-18T20:28:40.712Z
Learning: Files under `packages/sync-server/src/app-gocardless/banks/` should not be converted from JavaScript to TypeScript as part of currency decimal precision PRs. TypeScript migration for bank adapters should be handled separately in dedicated PRs.

Learnt from: matt-fidd
Repo: actualbudget/actual PR: 6010
File: packages/sync-server/src/app-sync.ts:331-331
Timestamp: 2025-10-27T17:06:08.172Z
Learning: The logger should only be used in loot-core code. In sync-server code (packages/sync-server), using console methods (console.error, console.log, etc.) is acceptable.

Learnt from: matt-fidd
Repo: actualbudget/actual PR: 3581
File: packages/loot-core/src/types/models/bank-sync.d.ts:11-21
Timestamp: 2024-11-04T14:14:10.698Z
Learning: In `packages/loot-core/src/types/models/bank-sync.d.ts`, when defining TypeScript types for data received from the server, maintain the field names as they are in the server response, even if they don't follow TypeScript naming conventions.

Learnt from: MikesGlitch
Repo: actualbudget/actual PR: 3553
File: packages/desktop-electron/package.json:88-88
Timestamp: 2024-10-04T08:48:55.161Z
Learning: In the `desktop-electron` module, `loot-core`'s essential files are intentionally copied during packaging using `electron-builder`. Therefore, references to `loot-core` in the codebase are expected and should remain, even though the `loot-core` dependency is removed from `package.json`.

Learnt from: CR
Repo: actualbudget/actual PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-02-14T07:59:10.247Z
Learning: Applies to packages/loot-core/**/*.{ts,tsx} : Don't import `actual-app/web/*` in `loot-core`

Learnt from: matt-fidd
Repo: actualbudget/actual PR: 3581
File: packages/loot-core/src/server/main.ts:1188-1198
Timestamp: 2024-10-25T00:12:14.939Z
Learning: In `packages/loot-core/src/server/main.ts`, when handling errors, the error properties `error_code` and `error_type` may already be mapped to `code` and `category` before being passed to `handleSyncError`.

Learnt from: matt-fidd
Repo: actualbudget/actual PR: 3581
File: packages/loot-core/src/client/actions/account.ts:180-194
Timestamp: 2024-11-04T00:34:13.035Z
Learning: In `packages/loot-core/src/client/actions/account.ts`, within the `syncAccounts` function, the batch sync request for SimpleFin accounts handles errors by returning error objects instead of throwing exceptions. Therefore, wrapping this block in a try-catch is unnecessary.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 5908
File: packages/desktop-client/src/components/settings/Currency.tsx:38-38
Timestamp: 2025-10-24T16:51:43.421Z
Learning: In the actualbudget/actual repository, JPY (Japanese Yen) currency support can remain enabled in packages/desktop-client/src/components/settings/Currency.tsx and packages/loot-core/src/shared/currencies.ts even though not all features fully support zero-decimal currencies yet, because the currency feature is experimental. The team decided to keep JPY active to avoid repeatedly removing and re-adding it during testing.

Learnt from: MatissJanis
Repo: actualbudget/actual PR: 5770
File: packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx:818-829
Timestamp: 2025-09-22T20:22:25.375Z
Learning: MatissJanis prefers to keep PR scope isolated to the main objective (like TS upgrades) and avoid including additional patches/improvements outside of that scope, even if they would be beneficial.

Learnt from: MatissJanis
Repo: actualbudget/actual PR: 5770
File: packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx:229-230
Timestamp: 2025-09-22T20:22:12.747Z
Learning: MatissJanis prefers to keep TypeScript conversion PRs focused on just the TS upgrade without additional patches/improvements to maintain manageable PR scope.

Learnt from: antran22
Repo: actualbudget/actual PR: 6902
File: packages/loot-core/src/shared/currencies.ts:0-0
Timestamp: 2026-02-08T06:07:24.555Z
Learning: In the actualbudget/actual repository, Vietnamese Dong (VND) in packages/loot-core/src/shared/currencies.ts uses decimalPlaces: 2 instead of the technically correct decimalPlaces: 0, because zero-decimal currency support is incomplete. Using decimalPlaces: 0 causes a 100x multiplication bug where input amounts are stored incorrectly. This is the same issue affecting JPY and other zero-decimal currencies.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:64-72
Timestamp: 2025-06-16T17:45:40.807Z
Learning: The user misu-dev prefers strict type checking for financial format types in useFormat.ts as a long-term goal, but acknowledges that creating follow-up issues for cleanup should wait until after the current PR is merged, not during the development phase.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 19, 2026

@StephenBrown2, kicking off a review of the latest changes now!


🧠 Learnings used
Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/loot-core/src/server/accounts/sync.ts:458-462
Timestamp: 2026-03-12T19:43:17.236Z
Learning: In `packages/loot-core/src/server/accounts/sync.ts`, the `amountToInteger(trans.amount, 2)` call in `normalizeBankSyncTransactions` intentionally hardcodes 2 decimal places because all current bank sync providers (GoCardless, SimpleFin, Pluggy.ai) only support currencies with 2 decimal places. This should be revisited and flagged again only when a bank sync provider is added that supports non-two-decimal currencies (e.g., JPY/VND with 0 decimals, or KWD with 3 decimals).

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/loot-core/src/server/transactions/export/export-to-csv.ts:9-15
Timestamp: 2026-03-12T19:41:44.132Z
Learning: In `packages/loot-core/src/server/transactions/export/export-to-csv.ts`, the `getDecimalPlaces()` helper intentionally uses a single global `defaultCurrencyCode` for all exported rows because accounts do not have individual currencies yet. Per-account currency formatting (e.g., using `account.currency` per row) should only be applied once multi-currency per-account support is implemented. Flag this again when individual accounts gain a `currency` field.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/loot-core/src/server/rules/action.ts:319-320
Timestamp: 2026-02-26T20:02:30.989Z
Learning: In packages/loot-core/src/server/rules/action.ts, the executeFormulaSync method calls amountToInteger(cellValue) without a decimalPlaces parameter (line 320), which defaults to 2 decimal places. This is a known limitation that will remain until multi-currency account support is implemented, as DbAccount does not currently have a currency field to determine per-account decimal precision for formula results.

Learnt from: antran22
Repo: actualbudget/actual PR: 6902
File: packages/loot-core/src/shared/currencies.ts:0-0
Timestamp: 2026-02-08T06:07:24.555Z
Learning: In the actualbudget/actual repository, Vietnamese Dong (VND) in packages/loot-core/src/shared/currencies.ts uses decimalPlaces: 2 instead of the technically correct decimalPlaces: 0, because zero-decimal currency support is incomplete. Using decimalPlaces: 0 causes a 100x multiplication bug where input amounts are stored incorrectly. This is the same issue affecting JPY and other zero-decimal currencies.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:64-72
Timestamp: 2025-06-16T17:45:40.807Z
Learning: The user misu-dev prefers strict type checking for financial format types in useFormat.ts as a long-term goal, but acknowledges that creating follow-up issues for cleanup should wait until after the current PR is merged, not during the development phase.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/sync-server/src/app-gocardless/banks/ing_ingddeff.js:1-2
Timestamp: 2026-02-18T20:28:46.629Z
Learning: Files under `packages/sync-server/src/app-gocardless/banks/` should not be converted from JavaScript to TypeScript as part of currency decimal precision PRs. TypeScript migration for bank adapters should be handled separately in dedicated PRs.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 6954
File: packages/sync-server/src/app-gocardless/banks/american_express_aesudef1.js:1-2
Timestamp: 2026-02-18T20:28:32.168Z
Learning: In the actualbudget/actual repository, JavaScript files under packages/sync-server/src/app-gocardless/banks/ should not be converted to TypeScript in code reviews. These bank integration files are intentionally kept as JS and will be migrated to TypeScript in a separate coordinated effort.

Learnt from: StephenBrown2
Repo: actualbudget/actual PR: 5908
File: packages/desktop-client/src/components/settings/Currency.tsx:38-38
Timestamp: 2025-10-24T16:51:43.421Z
Learning: In the actualbudget/actual repository, JPY (Japanese Yen) currency support can remain enabled in packages/desktop-client/src/components/settings/Currency.tsx and packages/loot-core/src/shared/currencies.ts even though not all features fully support zero-decimal currencies yet, because the currency feature is experimental. The team decided to keep JPY active to avoid repeatedly removing and re-adding it during testing.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:222-229
Timestamp: 2025-06-14T20:50:58.830Z
Learning: The `currencyToAmount` function in `loot-core/shared/util.ts` converts currency strings (like "3.14") directly to numeric amounts (3.14) without taking decimal places as a parameter. It only parses the string format and does not handle decimal place scaling - that happens downstream in functions like `amountToInteger` and `fromAmount`.

Learnt from: lelemm
Repo: actualbudget/actual PR: 5939
File: packages/desktop-client/src/hooks/useTransactionFormulaExecution.ts:53-76
Timestamp: 2025-10-17T13:16:39.862Z
Learning: In the Formula feature, monetary value conversion (raw integer cents to financial numbers, e.g., dividing by 100) is only needed when executing queries via the `QUERY()` function in `useFormulaExecution.ts`. The `useTransactionFormulaExecution.ts` hook handles transaction field values directly and does not require monetary conversion, as the values are already in the expected format.

Learnt from: sjones512
Repo: actualbudget/actual PR: 5554
File: packages/desktop-client/src/components/reports/spreadsheets/crossover-spreadsheet.ts:375-387
Timestamp: 2025-08-16T07:09:15.691Z
Learning: When handling financial data consistency issues in the desktop client, prefer keeping the data layer (spreadsheets) in raw integer cents and use the useFormat hook for all presentation formatting, rather than converting to display amounts in the data layer.

Learnt from: misu-dev
Repo: actualbudget/actual PR: 5167
File: packages/desktop-client/src/components/spreadsheet/useFormat.ts:161-166
Timestamp: 2025-06-14T21:20:46.938Z
Learning: In the useFormat hook's formatDisplay function, there's an intentional separation between displayDecimalPlaces (used for Intl.NumberFormat display formatting) and activeCurrency.decimalPlaces (used for integerToCurrency conversion logic). These should not be mixed as displayDecimalPlaces controls how many decimals to show while activeCurrency.decimalPlaces controls the mathematical conversion from integer amounts to decimal amounts.
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

This comment has been minimized.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/loot-core/src/server/importers/ynab5.ts (1)

1189-1218: ⚠️ Potential issue | 🔴 Critical

Set the imported budget's default currency from data.currency_format.iso_code.

The code now stores integer amounts using the correct decimal precision from the YNAB budget, but it never persists data.currency_format.iso_code to the defaultCurrencyCode preference. After a JPY/VND/KWD import completes, the app will render and edit transactions at the wrong scale because defaultCurrencyCode remains unset (empty). Add a call to set the currency before import completion:

await send('preferences/save', {
  id: 'defaultCurrencyCode',
  value: data.currency_format?.iso_code ?? '',
});

Place this in doImport() after importing budgets or in the "Setting up..." section.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/loot-core/src/server/importers/ynab5.ts` around lines 1189 - 1218,
The import flow never persists the YNAB budget currency, so defaultCurrencyCode
stays empty; update doImport to save data.currency_format.iso_code into
preferences by calling send('preferences/save', { id: 'defaultCurrencyCode',
value: data.currency_format?.iso_code ?? '' }) after importBudgets completes (or
in the "Setting up..." section) so the app uses the correct default currency for
amounts; locate doImport and place the preference save call after importBudgets
(using the existing send function and the defaultCurrencyCode preference id).
♻️ Duplicate comments (1)
packages/loot-core/src/server/importers/ynab5.ts (1)

77-90: ⚠️ Potential issue | 🟠 Major

Fail fast when the YNAB currency metadata can't be resolved.

getCurrency(cf?.iso_code ?? '') returns the default currency entry on a miss, so malformed or newly added YNAB ISO codes still silently fall back to 2 decimals here. That recreates the same wrong-scale persistence path this PR is trying to remove. Please validate the ISO lookup and throw if neither decimal_digits nor a recognized iso_code is available.

Suggested fix
 function getYnab5DecimalPlaces(data: Budget): number {
   const cf = data.currency_format;
   // Prefer API decimal_digits (including 0 for zero-decimal currencies); fall back to ISO code.
   const decimalPlaces = cf?.decimal_digits;
   if (
     typeof decimalPlaces === 'number' &&
     Number.isInteger(decimalPlaces) &&
     decimalPlaces >= 0 &&
     decimalPlaces <= 10
   ) {
     return decimalPlaces;
   }
-  return getCurrency(cf?.iso_code ?? '').decimalPlaces;
+  if (cf?.iso_code) {
+    const currency = getCurrency(cf.iso_code);
+    if (currency.code === cf.iso_code) {
+      return currency.decimalPlaces;
+    }
+  }
+  throw new Error(
+    `Unsupported YNAB currency metadata: iso_code=${String(cf?.iso_code)}, decimal_digits=${String(cf?.decimal_digits)}`,
+  );
 }
Based on learnings: In `packages/loot-core/src/shared/currencies.ts`, using `decimalPlaces: 2` for VND caused a 100x multiplication bug when zero-decimal currencies were treated as 2-decimal values.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/loot-core/src/server/importers/ynab5.ts` around lines 77 - 90, The
getYnab5DecimalPlaces function currently falls back to getCurrency(cf?.iso_code
?? '').decimalPlaces which silently returns a default and can mis-scale amounts;
change getYnab5DecimalPlaces to first check cf?.decimal_digits as now, then if
absent/invalid validate that cf?.iso_code is non-empty and that
getCurrency(cf.iso_code) returns a known currency (not the default/miss) and
throw an error if the ISO lookup fails so we fail-fast on unknown YNAB ISO codes
instead of silently using a default decimalPlaces; reference
getYnab5DecimalPlaces, cf?.decimal_digits, cf?.iso_code, and getCurrency in the
fix.
🧹 Nitpick comments (2)
packages/desktop-client/src/components/transactions/table/utils.test.ts (1)

17-61: Reduce duplicated round-trip tests with a table-driven pattern.

The 0/2/3 decimal tests repeat the same structure; using test.each will make future currency precision additions easier and less error-prone.

♻️ Suggested refactor
 describe('transaction table utils decimal places', () => {
-  test('serializes and deserializes zero-decimal currencies', () => {
-    const original = makeTransaction(1000000);
-
-    const serialized = serializeTransaction(original, 0, false);
-    expect(serialized.credit).toBe('1,000,000');
-    expect(serialized.debit).toBe('');
-
-    const deserialized = deserializeTransaction(serialized, original, 0);
-    expect(deserialized.amount).toBe(1000000);
-  });
-
-  test('serializes and deserializes two-decimal currencies', () => {
-    const original = makeTransaction(1000000);
-
-    const serialized = serializeTransaction(original, 2, false);
-    expect(serialized.credit).toBe('10,000.00');
-    expect(serialized.debit).toBe('');
-
-    const deserialized = deserializeTransaction(serialized, original, 2);
-    expect(deserialized.amount).toBe(1000000);
-  });
-
-  test('serializes and deserializes three-decimal currencies', () => {
-    const original = makeTransaction(1000000);
-
-    const serialized = serializeTransaction(original, 3, false);
-    expect(serialized.credit).toBe('1,000.000');
-    expect(serialized.debit).toBe('');
-
-    const deserialized = deserializeTransaction(serialized, original, 3);
-    expect(deserialized.amount).toBe(1000000);
-  });
+  type CreditCase = {
+    name: string;
+    decimalPlaces: number;
+    expectedCredit: string;
+  };
+
+  const creditCases: CreditCase[] = [
+    {
+      name: 'serializes and deserializes zero-decimal currencies',
+      decimalPlaces: 0,
+      expectedCredit: '1,000,000',
+    },
+    {
+      name: 'serializes and deserializes two-decimal currencies',
+      decimalPlaces: 2,
+      expectedCredit: '10,000.00',
+    },
+    {
+      name: 'serializes and deserializes three-decimal currencies',
+      decimalPlaces: 3,
+      expectedCredit: '1,000.000',
+    },
+  ];
+
+  test.each(creditCases)('$name', ({ decimalPlaces, expectedCredit }) => {
+    const original = makeTransaction(1000000);
+    const serialized = serializeTransaction(original, decimalPlaces, false);
+    expect(serialized.credit).toBe(expectedCredit);
+    expect(serialized.debit).toBe('');
+
+    const deserialized = deserializeTransaction(
+      serialized,
+      original,
+      decimalPlaces,
+    );
+    expect(deserialized.amount).toBe(1000000);
+  });

As per coding guidelines: "Prefer iteration and modularization over code duplication".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/transactions/table/utils.test.ts`
around lines 17 - 61, Replace the three near-identical decimal-precision tests
with a table-driven parameterized test using test.each: create a table of cases
with columns for decimals (0,2,3), input amount (1000000), and the expected
serialized credit string ('1,000,000', '10,000.00', '1,000.000'), then inside
the test call makeTransaction, serializeTransaction(decimals), assert
serialized.credit and serialized.debit, and round-trip using
deserializeTransaction to assert deserialized.amount; keep the negative/debit
scenario either as a separate test or add a row with amount -1000000 and
expected debit string ('10,000.00') to the same table. Ensure you reference the
existing helpers serializeTransaction, deserializeTransaction, and
makeTransaction so the refactor only changes the test scaffolding, not the
logic.
packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx (1)

172-185: Make decimalPlaces required instead of silently defaulting to 2.

The prop is already threaded from CategoryList, so keeping decimalPlaces?: number plus ?? 2 just leaves a quiet path back to the regression this PR is fixing. Prefer a required prop and let TypeScript catch any missed wiring.

♻️ Suggested tightening
 type CategoryItemProps = {
   item: CategoryAutocompleteItem;
   className?: string;
   style?: CSSProperties;
   highlighted?: boolean;
   embedded?: boolean;
   showBalances?: boolean;
-  decimalPlaces?: number;
+  decimalPlaces: number;
 };
@@
-                    {integerToCurrency(toBudget || 0, decimalPlaces ?? 2)}
+                    {integerToCurrency(toBudget || 0, decimalPlaces)}
@@
-                    {integerToCurrency(balance || 0, decimalPlaces ?? 2)}
+                    {integerToCurrency(balance || 0, decimalPlaces)}

Also applies to: 434-445, 512-525

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx`
around lines 172 - 185, The code currently silently defaults decimalPlaces to 2
which hides wiring errors; make decimalPlaces a required prop and remove any
fallback defaults (the `?? 2` usage) so TypeScript will surface missing props.
Update the prop/type definitions that pass decimalPlaces (e.g., the
CategoryList/CategoryAutocomplete props and any interfaces referencing
decimalPlaces) to require number, and remove the `?? 2` in call sites such as
the renderCategoryItem invocation (and the other occurrences around the file
where decimalPlaces is defaulted) so callers must provide decimalPlaces
explicitly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/desktop-client/e2e/page-models/settings-page.ts`:
- Around line 103-118: In selectCurrency, guard against empty or whitespace-only
currencyCode before building the locator (which currently produces name: ' -'
and causes long timeouts); trim currencyCode and if it's empty throw a clear
synchronous Error (or return early) so callers get immediate feedback; update
the validation near the start of selectCurrency (before using
dropdownTrigger/currencyMenu/currencyOption) to ensure a non-empty ISO code is
provided.

In
`@packages/desktop-client/src/components/mobile/transactions/FocusableAmountInput.tsx`:
- Around line 112-117: The input currently only flashes and sets
showFractionError when too many decimals are entered (see applyText and
flashFractionError in FocusableAmountInput), so add a visible, accessible error
message element (e.g., a small inline text node tied to an aria-live="assertive"
region) and a piece of state like fractionErrorMessage to hold the message;
update flashFractionError (and any other places that set showFractionError
around lines 149-153 and 177-187) to set fractionErrorMessage to a user-facing
string and showFractionError true, render the message next to the input so it’s
visible on touch, and ensure it is announced by assistive tech via aria-live and
cleared/reset when the value changes or the error resolves.

---

Outside diff comments:
In `@packages/loot-core/src/server/importers/ynab5.ts`:
- Around line 1189-1218: The import flow never persists the YNAB budget
currency, so defaultCurrencyCode stays empty; update doImport to save
data.currency_format.iso_code into preferences by calling
send('preferences/save', { id: 'defaultCurrencyCode', value:
data.currency_format?.iso_code ?? '' }) after importBudgets completes (or in the
"Setting up..." section) so the app uses the correct default currency for
amounts; locate doImport and place the preference save call after importBudgets
(using the existing send function and the defaultCurrencyCode preference id).

---

Duplicate comments:
In `@packages/loot-core/src/server/importers/ynab5.ts`:
- Around line 77-90: The getYnab5DecimalPlaces function currently falls back to
getCurrency(cf?.iso_code ?? '').decimalPlaces which silently returns a default
and can mis-scale amounts; change getYnab5DecimalPlaces to first check
cf?.decimal_digits as now, then if absent/invalid validate that cf?.iso_code is
non-empty and that getCurrency(cf.iso_code) returns a known currency (not the
default/miss) and throw an error if the ISO lookup fails so we fail-fast on
unknown YNAB ISO codes instead of silently using a default decimalPlaces;
reference getYnab5DecimalPlaces, cf?.decimal_digits, cf?.iso_code, and
getCurrency in the fix.

---

Nitpick comments:
In
`@packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx`:
- Around line 172-185: The code currently silently defaults decimalPlaces to 2
which hides wiring errors; make decimalPlaces a required prop and remove any
fallback defaults (the `?? 2` usage) so TypeScript will surface missing props.
Update the prop/type definitions that pass decimalPlaces (e.g., the
CategoryList/CategoryAutocomplete props and any interfaces referencing
decimalPlaces) to require number, and remove the `?? 2` in call sites such as
the renderCategoryItem invocation (and the other occurrences around the file
where decimalPlaces is defaulted) so callers must provide decimalPlaces
explicitly.

In `@packages/desktop-client/src/components/transactions/table/utils.test.ts`:
- Around line 17-61: Replace the three near-identical decimal-precision tests
with a table-driven parameterized test using test.each: create a table of cases
with columns for decimals (0,2,3), input amount (1000000), and the expected
serialized credit string ('1,000,000', '10,000.00', '1,000.000'), then inside
the test call makeTransaction, serializeTransaction(decimals), assert
serialized.credit and serialized.debit, and round-trip using
deserializeTransaction to assert deserialized.amount; keep the negative/debit
scenario either as a separate test or add a row with amount -1000000 and
expected debit string ('10,000.00') to the same table. Ensure you reference the
existing helpers serializeTransaction, deserializeTransaction, and
makeTransaction so the refactor only changes the test scaffolding, not the
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 856a3c64-b280-4fe9-ad86-bae2332878fd

📥 Commits

Reviewing files that changed from the base of the PR and between e256063 and 0372442.

📒 Files selected for processing (52)
  • packages/desktop-client/e2e/accounts.test.ts
  • packages/desktop-client/e2e/budget.test.ts
  • packages/desktop-client/e2e/currency-precision.ts
  • packages/desktop-client/e2e/page-models/settings-page.ts
  • packages/desktop-client/e2e/transactions.test.ts
  • packages/desktop-client/src/accounts/mutations.ts
  • packages/desktop-client/src/components/accounts/Account.tsx
  • packages/desktop-client/src/components/accounts/BalanceHistoryGraph.tsx
  • packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx
  • packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
  • packages/desktop-client/src/components/budget/envelope/CoverMenu.tsx
  • packages/desktop-client/src/components/budget/util.ts
  • packages/desktop-client/src/components/mobile/transactions/FocusableAmountInput.tsx
  • packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx
  • packages/desktop-client/src/components/mobile/transactions/TransactionList.tsx
  • packages/desktop-client/src/components/mobile/transactions/TransactionListItem.tsx
  • packages/desktop-client/src/components/modals/CloseAccountModal.tsx
  • packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx
  • packages/desktop-client/src/components/modals/EditFieldModal.tsx
  • packages/desktop-client/src/components/modals/EnvelopeBudgetMenuModal.tsx
  • packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx
  • packages/desktop-client/src/components/modals/TrackingBudgetMenuModal.tsx
  • packages/desktop-client/src/components/settings/Currency.tsx
  • packages/desktop-client/src/components/transactions/TransactionsTable.test.tsx
  • packages/desktop-client/src/components/transactions/TransactionsTable.tsx
  • packages/desktop-client/src/components/transactions/table/utils.test.ts
  • packages/desktop-client/src/components/transactions/table/utils.ts
  • packages/desktop-client/src/hooks/useFormat.ts
  • packages/desktop-client/src/hooks/useFormulaExecution.ts
  • packages/desktop-client/src/hooks/useTransactionsSearch.ts
  • packages/desktop-client/src/queries/index.ts
  • packages/loot-core/src/server/accounts/app.ts
  • packages/loot-core/src/server/accounts/sync.ts
  • packages/loot-core/src/server/api.ts
  • packages/loot-core/src/server/budget/actions.ts
  • packages/loot-core/src/server/budget/category-template-context.test.ts
  • packages/loot-core/src/server/budget/category-template-context.ts
  • packages/loot-core/src/server/budget/schedule-template.ts
  • packages/loot-core/src/server/importers/ynab4.ts
  • packages/loot-core/src/server/importers/ynab5.ts
  • packages/loot-core/src/server/rules/action.ts
  • packages/loot-core/src/server/rules/customFunctions.ts
  • packages/loot-core/src/server/rules/index.test.ts
  • packages/loot-core/src/server/transactions/export/export-to-csv.ts
  • packages/loot-core/src/server/transactions/import/parse-file.test.ts
  • packages/loot-core/src/server/transactions/transaction-rules.ts
  • packages/loot-core/src/shared/currencies.ts
  • packages/loot-core/src/shared/util.test.ts
  • packages/loot-core/src/shared/util.ts
  • packages/loot-core/src/types/models/bank-sync.ts
  • upcoming-release-notes/6902.md
  • upcoming-release-notes/6954.md
✅ Files skipped from review due to trivial changes (13)
  • packages/desktop-client/src/components/settings/Currency.tsx
  • upcoming-release-notes/6902.md
  • packages/desktop-client/e2e/budget.test.ts
  • upcoming-release-notes/6954.md
  • packages/desktop-client/src/components/modals/CloseAccountModal.tsx
  • packages/loot-core/src/server/budget/schedule-template.ts
  • packages/desktop-client/src/components/modals/TrackingBudgetMenuModal.tsx
  • packages/loot-core/src/shared/currencies.ts
  • packages/desktop-client/src/components/mobile/transactions/TransactionList.tsx
  • packages/loot-core/src/types/models/bank-sync.ts
  • packages/desktop-client/e2e/transactions.test.ts
  • packages/desktop-client/src/components/mobile/transactions/TransactionEdit.tsx
  • packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx
🚧 Files skipped from review as they are similar to previous changes (24)
  • packages/loot-core/src/server/rules/customFunctions.ts
  • packages/desktop-client/src/accounts/mutations.ts
  • packages/desktop-client/src/components/accounts/BalanceHistoryGraph.tsx
  • packages/desktop-client/src/hooks/useTransactionsSearch.ts
  • packages/loot-core/src/server/rules/index.test.ts
  • packages/loot-core/src/server/transactions/import/parse-file.test.ts
  • packages/loot-core/src/server/importers/ynab4.ts
  • packages/loot-core/src/server/accounts/app.ts
  • packages/loot-core/src/server/budget/category-template-context.ts
  • packages/desktop-client/src/queries/index.ts
  • packages/desktop-client/src/components/modals/CreateLocalAccountModal.tsx
  • packages/desktop-client/src/components/accounts/Account.tsx
  • packages/desktop-client/src/components/modals/ImportTransactionsModal/ImportTransactionsModal.tsx
  • packages/desktop-client/e2e/accounts.test.ts
  • packages/desktop-client/src/components/transactions/table/utils.ts
  • packages/loot-core/src/server/transactions/transaction-rules.ts
  • packages/loot-core/src/server/budget/actions.ts
  • packages/desktop-client/src/components/transactions/TransactionsTable.test.tsx
  • packages/loot-core/src/shared/util.test.ts
  • packages/desktop-client/e2e/currency-precision.ts
  • packages/desktop-client/src/hooks/useFormat.ts
  • packages/desktop-client/src/components/transactions/TransactionsTable.tsx
  • packages/loot-core/src/server/transactions/export/export-to-csv.ts
  • packages/desktop-client/src/components/modals/EditFieldModal.tsx

Comment thread packages/desktop-client/e2e/page-models/settings-page.ts
@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
packages/desktop-client/e2e/page-models/settings-page.ts (1)

45-77: Consider adding an explicit return type annotation.

The private helper correctly centralizes the expand/collapse logic and visibility handling. For consistency with the public methods and improved maintainability, consider adding the explicit return type.

- private async getExperimentalFeatureCheckbox(featureName: string) {
+ private async getExperimentalFeatureCheckbox(featureName: string): Promise<Locator> {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/desktop-client/e2e/page-models/settings-page.ts` around lines 45 -
77, The method getExperimentalFeatureCheckbox lacks an explicit return type;
update its signature to include the proper Promise return type (e.g., add ":
Promise<Locator>") so callers and maintainers see the expected Playwright
Locator result, and if Locator isn't already imported in this file add the
import from Playwright (for example from '@playwright/test').
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/desktop-client/e2e/page-models/settings-page.ts`:
- Around line 45-77: The method getExperimentalFeatureCheckbox lacks an explicit
return type; update its signature to include the proper Promise return type
(e.g., add ": Promise<Locator>") so callers and maintainers see the expected
Playwright Locator result, and if Locator isn't already imported in this file
add the import from Playwright (for example from '@playwright/test').

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6069e086-1516-47c0-bd64-f33f2c2d9848

📥 Commits

Reviewing files that changed from the base of the PR and between 0372442 and 60db61a.

⛔ Files ignored due to path filters (296)
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-7-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-8-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-9-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-the-accounts-page-and-asserts-on-balances-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-the-accounts-page-and-asserts-on-balances-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-the-accounts-page-and-asserts-on-balances-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-import-csv-file-twice-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-import-csv-file-twice-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-import-csv-file-twice-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-imports-transactions-from-a-CSV-file-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-imports-transactions-from-a-CSV-file-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Import-Transactions-imports-transactions-from-a-CSV-file-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-creates-a-new-account-and-views-the-initial-balance-transaction-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-creates-a-new-account-and-views-the-initial-balance-transaction-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-creates-a-new-account-and-views-the-initial-balance-transaction-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-page-handles-empty-state-gracefully-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-page-handles-empty-state-gracefully-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-page-handles-empty-state-gracefully-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-searches-for-accounts-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-searches-for-accounts-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.mobile.test.ts-snapshots/Mobile-Bank-Sync-searches-for-accounts-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.test.ts-snapshots/Bank-Sync-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.test.ts-snapshots/Bank-Sync-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/bank-sync.test.ts-snapshots/Bank-Sync-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-applies-budget-template-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-applies-budget-template-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-applies-budget-template-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--14404-in-the-page-header-opens-the-month-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--321fd-ed-amount-opens-the-budget-summary-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--4bb70-ed-amount-opens-the-budget-summary-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--589a6-the-page-header-shows-the-next-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--6ab37-roup-name-opens-the-category-group-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--6dbdb-page-header-shows-the-previous-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--7bd8f-the-page-header-shows-the-next-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--884ac-the-page-header-shows-the-next-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--94a79-roup-name-opens-the-category-group-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--94a85-ed-amount-opens-the-budget-summary-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--96ebb-page-header-shows-the-previous-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--9e6aa-in-the-page-header-opens-the-budget-page-menu-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--bbde3-roup-name-opens-the-category-group-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--bed18-in-the-page-header-opens-the-month-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--c18ad-l-redirects-to-the-category-transactions-page-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--ceb3a-in-the-page-header-opens-the-month-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--d270d-in-the-page-header-opens-the-budget-page-menu-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--d7184-page-header-shows-the-previous-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--e995e-l-redirects-to-the-category-transactions-page-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--fdd57-in-the-page-header-opens-the-budget-page-menu-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking--ff568-l-redirects-to-the-category-transactions-page-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-category-name-opens-the-category-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-category-name-opens-the-category-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-checks-that-clicking-the-category-name-opens-the-category-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-copies-last-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-copies-last-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-copies-last-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-loads-the-budget-page-with-budgeted-amounts-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-12-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-12-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-12-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-3-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-3-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-3-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-6-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-6-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-set-budget-to-6-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-updates-the-budgeted-amount-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-updates-the-budgeted-amount-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Envelope-updates-the-budgeted-amount-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-applies-budget-template-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-applies-budget-template-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-applies-budget-template-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--0ba04-nt-amount-opens-the-budget-summary-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--0dfe7-page-header-shows-the-previous-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--11290-l-redirects-to-the-category-transactions-page-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--1ce6d-nt-amount-opens-the-budget-summary-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--42062-in-the-page-header-opens-the-month-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--49fb6-in-the-page-header-opens-the-month-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--57d88-l-redirects-to-the-category-transactions-page-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--5d90c-l-redirects-to-the-category-transactions-page-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--5f098-roup-name-opens-the-category-group-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--7c353-the-page-header-shows-the-next-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--929be-roup-name-opens-the-category-group-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--a3783-in-the-page-header-opens-the-budget-page-menu-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--a8b5e-in-the-page-header-opens-the-budget-page-menu-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--b1562-in-the-page-header-opens-the-month-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--cfb69-page-header-shows-the-previous-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--d5af6-the-page-header-shows-the-next-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--dc927-roup-name-opens-the-category-group-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--f2198-the-page-header-shows-the-next-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--f224f-nt-amount-opens-the-budget-summary-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--f7fa3-page-header-shows-the-previous-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking--f8a19-in-the-page-header-opens-the-budget-page-menu-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-balance-cell-opens-the-balance-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-budgeted-cell-opens-the-budget-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-category-name-opens-the-category-menu-modal-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-category-name-opens-the-category-menu-modal-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-checks-that-clicking-the-category-name-opens-the-category-menu-modal-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-copies-last-month-s-budget-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-copies-last-month-s-budget-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-copies-last-month-s-budget-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-loads-the-budget-page-with-budgeted-amounts-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-loads-the-budget-page-with-budgeted-amounts-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-loads-the-budget-page-with-budgeted-amounts-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-12-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-12-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-12-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-3-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-3-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-3-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-6-month-average-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-6-month-average-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-set-budget-to-6-month-average-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-updates-the-budgeted-amount-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-updates-the-budgeted-amount-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.mobile.test.ts-snapshots/Mobile-Budget-Tracking-updates-the-budgeted-amount-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-renders-the-summary-information-available-funds-overspent-budgeted-and-for-next-month-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-renders-the-summary-information-available-funds-overspent-budgeted-and-for-next-month-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-renders-the-summary-information-available-funds-overspent-budgeted-and-for-next-month-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-transfer-funds-to-another-category-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-transfer-funds-to-another-category-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-transfer-funds-to-another-category-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-search-works-correctly-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-search-works-correctly-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-search-works-correctly-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/command-bar.test.ts-snapshots/Command-bar-Check-the-command-bar-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-help-menu-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-help-menu-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-help-menu-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-7-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-8-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/help-menu.test.ts-snapshots/Help-menu-Check-the-keyboard-shortcuts-modal-visuals-9-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/onboarding.test.ts-snapshots/Onboarding-checks-the-page-visuals-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-payee-edit-page-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-rule-creation-form-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-rule-creation-form-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-clicking-on-a-payee-opens-rule-creation-form-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-filters-out-unrelated-payees-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-filters-out-unrelated-payees-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-filters-out-unrelated-payees-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-page-handles-empty-state-gracefully-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-page-handles-empty-state-gracefully-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-page-handles-empty-state-gracefully-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.mobile.test.ts-snapshots/Mobile-Payees-search-functionality-works-correctly-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/payees.test.ts-snapshots/Payees-checks-the-payees-page-visuals-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Area-Graph-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Area-Graph-and-checks-the-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Area-Graph-and-checks-the-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Bar-Graph-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Bar-Graph-and-checks-the-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Bar-Graph-and-checks-the-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Data-Table-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Data-Table-and-checks-the-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Data-Table-and-checks-the-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Line-Graph-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Line-Graph-and-checks-the-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Line-Graph-and-checks-the-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-labels-button-shows-the-labels-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-labels-button-shows-the-labels-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-labels-button-shows-the-labels-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-legend-button-shows-the-legend-side-bar-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-legend-button-shows-the-legend-side-bar-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-legend-button-shows-the-legend-side-bar-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-summary-button-shows-the-summary-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-summary-button-shows-the-summary-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-summary-button-shows-the-summary-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-cash-flow-graph-and-checks-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-cash-flow-graph-and-checks-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-cash-flow-graph-and-checks-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-and-cash-flow-reports-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-and-cash-flow-reports-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-and-cash-flow-reports-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-graph-and-checks-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-graph-and-checks-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-loads-net-worth-graph-and-checks-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-add-button-opens-rule-creation-form-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-add-button-opens-rule-creation-form-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-add-button-opens-rule-creation-form-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-on-a-rule-opens-edit-form-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-on-a-rule-opens-edit-form-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-clicking-on-a-rule-opens-edit-form-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-displays-the-rules-page-with-proper-header-and-search-bar-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-displays-the-rules-page-with-proper-header-and-search-bar-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-displays-the-rules-page-with-proper-header-and-search-bar-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-page-handles-empty-state-gracefully-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-page-handles-empty-state-gracefully-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-page-handles-empty-state-gracefully-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-search-functionality-filters-rules-correctly-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-search-functionality-filters-rules-correctly-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.mobile.test.ts-snapshots/Mobile-Rules-search-functionality-filters-rules-correctly-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/rules.test.ts-snapshots/Rules-creates-a-split-transaction-rule-and-makes-sure-it-is-applied-when-creating-a-transaction-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-clicking-on-a-schedule-opens-edit-form-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-clicking-on-a-schedule-opens-edit-form-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-clicking-on-a-schedule-opens-edit-form-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-displays-schedule-details-correctly-in-list-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-displays-schedule-details-correctly-in-list-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-displays-schedule-details-correctly-in-list-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-page-handles-empty-state-gracefully-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-page-handles-empty-state-gracefully-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-page-handles-empty-state-gracefully-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.mobile.test.ts-snapshots/Mobile-Schedules-searches-and-filters-schedules-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-checks-the-page-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-checks-the-page-visuals-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-checks-the-page-visuals-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-full-list-of-schedules-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-full-list-of-schedules-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-full-list-of-schedules-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-10-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-11-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-12-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-7-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/schedules.test.ts-snapshots/Schedules-creates-a-new-schedule-posts-the-transaction-and-later-completes-it-8-chromium-linux.png is excluded by !**/*.png
📒 Files selected for processing (4)
  • packages/desktop-client/e2e/accounts.test.ts
  • packages/desktop-client/e2e/budget.test.ts
  • packages/desktop-client/e2e/currency-precision.ts
  • packages/desktop-client/e2e/page-models/settings-page.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/desktop-client/e2e/budget.test.ts
  • packages/desktop-client/e2e/accounts.test.ts

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/vrt-update-generate.yml:
- Around line 108-125: The current loop applies the ±2KB filter to new or
deleted PNGs and then runs git restore --source=HEAD --staged --worktree --
"$f", which fails for files that don't exist in HEAD; modify the logic in the
png_paths loop (variables old, new, net, abs_net and the git restore invocation)
to only perform the byte-delta check and call git restore for files that exist
in both HEAD and the index (e.g., test git cat-file -e HEAD:"$f" && git cat-file
-e ":$f" or require old -gt 0 and new -gt 0 before computing net and executing
git restore) so new or deleted PNGs are skipped by the noise filter.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5d9284e4-7412-4925-8732-95f4f5aa0753

📥 Commits

Reviewing files that changed from the base of the PR and between 60db61a and 87d7ffc.

⛔ Files ignored due to path filters (45)
  • packages/desktop-client/e2e/accounts.mobile.test.ts-snapshots/Mobile-Accounts-opens-individual-account-page-and-checks-that-filtering-is-working-7-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-Default-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-Default-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-Default-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-JPY-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-JPY-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-JPY-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-KWD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-KWD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-KWD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-USD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-USD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-close-account-shows-correct-balance-for-USD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-Default-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-Default-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-Default-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-JPY-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-JPY-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-JPY-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-KWD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-KWD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-KWD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-USD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-USD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-Currency-Precision-starting-balance-displayed-correctly-for-USD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-4-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-5-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/accounts.test.ts-snapshots/Accounts-closes-an-account-with-transfer-6-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-Default-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-Default-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-Default-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-JPY-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-JPY-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-JPY-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-KWD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-KWD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-KWD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-USD-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-USD-2-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/budget.test.ts-snapshots/Budget-Currency-Precision-budget-page-displays-for-USD-3-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Switches-to-Donut-Graph-and-checks-the-visuals-1-chromium-linux.png is excluded by !**/*.png
  • packages/desktop-client/e2e/reports.test.ts-snapshots/Reports-custom-reports-Validates-that-show-legend-button-shows-the-legend-side-bar-1-chromium-linux.png is excluded by !**/*.png
📒 Files selected for processing (2)
  • .github/workflows/vrt-update-generate.yml
  • packages/desktop-client/e2e/page-models/settings-page.ts

Comment thread .github/workflows/vrt-update-generate.yml Outdated
@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

❌ Failed to apply VRT updates: Patch conflicts with current branch state

Please check the workflow logs for details.

@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@MikesGlitch
Copy link
Copy Markdown
Member

Hey @StephenBrown2 , just wanting to let you know it's highly unlikely that any of the maintainers are going to feel comfortable reviewing any pr this big. There's just too much in this PR.

To move anything forward for this you'd need to close this and open smaller PRs.

@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

Hey @MikesGlitch thanks for the update. Are you looking at the VRT changes primarily? I'm currently trying to work out a method to only retain used screenshots, and delete orphaned ones, since I renamed a VRT test and therefore some pngs should be renamed as well. Sorry for the churn on this PR while I work on reducing that blast effect.

If it's for the wide code changes, the sprawl is probably not easily containable, since adding decimalPlaces to every formatting function will require every call to be updated. How would you recommend the changes be divided up for easier review?

@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…d UI

Propagate decimalPlaces through shared amount utilities (including KWD), desktop and mobile UI, transactions, budgeting, search, importers, rules, and server account APIs. Add shared e2e currency-precision helpers and refactor related tests. Record attribution in upcoming release notes.
@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@github-actions

This comment has been minimized.

@StephenBrown2
Copy link
Copy Markdown
Contributor Author

/update-vrt

@github-actions
Copy link
Copy Markdown
Contributor

VRT tests ❌ failed. View the test report.

To update the VRT screenshots, comment /update-vrt on this PR. The VRT update operation takes about 50 minutes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

4 participants