[PR #8167] [AI] feat(currencies): decimal-aware amount handling in server #122380

Open
opened 2026-06-11 21:13:26 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/actualbudget/actual/pull/8167
Author: @StephenBrown2
Created: 6/9/2026
Status: 🔄 Open

Base: masterHead: feat/currency-decimal-server


📝 Commits (3)

  • d39ea4d [AI] feat(currencies): decimal-aware amount handling in importers, sync, export, rules, and API
  • 0c115dc [AI] test(currencies): update nYNAB onboarding e2e for currency symbol
  • 9baa004 [AI] fix(build): shim bare process in browser bundle so e2e can load

📊 Changes

14 files changed (+262 additions, -62 deletions)

View changed files

📝 packages/desktop-client/e2e/onboarding.test.ts (+6 -2)
📝 packages/desktop-client/vite.config.mts (+2 -0)
packages/loot-core/src/server/accounts/app.test.ts (+54 -0)
📝 packages/loot-core/src/server/accounts/app.ts (+4 -2)
📝 packages/loot-core/src/server/accounts/sync.ts (+59 -34)
📝 packages/loot-core/src/server/api.ts (+12 -4)
📝 packages/loot-core/src/server/importers/ynab4.ts (+15 -4)
📝 packages/loot-core/src/server/importers/ynab5.test.ts (+31 -0)
📝 packages/loot-core/src/server/importers/ynab5.ts (+19 -10)
📝 packages/loot-core/src/server/rules/action.ts (+10 -2)
📝 packages/loot-core/src/server/transactions/export/export-to-csv.ts (+10 -4)
packages/loot-core/src/server/util/currency.ts (+27 -0)
📝 packages/loot-core/src/shared/util.ts (+7 -0)
upcoming-release-notes/currency-decimal-server.md (+6 -0)

📄 Description

Description

Second part of the multi-currency implementation (i.e. DP-2). Implements decimal-aware amount encoding through all loot-core server paths so that currencies with non-standard decimal places (e.g. JPY at 0dp, KWD at 3dp) are stored and exported correctly rather than being assumed to be 2dp like USD.

PR stack: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc

  • DP-1: Currency metadata and decimal helper functions — #8064
  • DP-2: Server-side decimal-aware amount handling — This PR
  • DP-3: desktop-client: transaction table and search — TBD
  • DP-4: desktop-client: budget UI components — TBD
  • DP-5: desktop-client: modals, mobile, settings, and E2E — TBD
  • DP-6: Historical data migration for non-2dp currencies — TBD
  • DP-7: desktop-client: remove "hide decimal places" setting — TBD

Changes:

  • New packages/loot-core/src/server/util/currency.ts — shared helpers (getDefaultCurrencyCode, getDefaultCurrencyCodeSync, setDefaultCurrencyCode) that read/write the defaultCurrencyCode preference, replacing duplicated inline queries across server files.
  • New integerToCurrencyAmount(integer, code) in #shared/util — symmetric companion to the existing amountToCurrencyInteger.
  • YNAB5 importer: updates amountFromYnab to convert milliunits using the budget's currency precision, and sets defaultCurrencyCode from the budget's ISO code on import.
  • YNAB4 importer: uses amountToCurrencyInteger with the budget's currency instead of a hardcoded scale.
  • accounts/app.ts, accounts/sync.ts, rules/action.ts, transactions/export/export-to-csv.ts, api.ts: all replaced ad-hoc getDecimalPlaces + amountToInteger patterns with the new shared helpers.

No behavior change for existing 2dp budgets (USD, EUR, GBP, etc.).

Regression analysis for non-2dp budgets

Before this PR, all server paths hardcoded 2dp regardless of defaultCurrencyCode. The preference existed in the schema and was already exposed in the Settings UI (Currency.tsx) for client-side display formatting, but was never read by the server. This PR makes the server read it and apply the correct precision.

  • Existing budgets with no currency set: zero risk. Empty string falls back to 2dp via getDecimalPlaces, identical behavior to before.
  • Existing budgets with defaultCurrencyCode = 'JPY' (or other 0dp currency): Historical transactions were stored at 100x inflation by the old server code (¥1234 → integer 123400). The client masked this by combining 2dp display with the hideFraction pref (set automatically to true when a 0dp currency is selected in Settings), so ¥1234 stored as 123400 rendered as 1234.001234 — appearing correct. After this PR, new server writes produce correctly-encoded integers (¥1234 → 1234). The same client path then renders 1234 as 12.3412 via hideFraction, showing 1/100 of the correct value. So display was silently masked before; after this PR it visibly breaks for new transactions until DP-3 lands.
  • Client-side input (DP-3 not yet landed): the transaction entry UI still parses user input with 2dp assumptions. A JPY user typing ¥1234 in the UI will still produce integer 123400 via the client path, even though server-side writes (bank sync, YNAB import) now produce 1234. DP-3 is a fast-follow requirement to close this gap.
  • Budget templates (schedule-template.ts, category-template-context.ts, budget/actions.ts): not updated in this PR. Template amounts remain at 2dp while transaction amounts use the correct precision for non-2dp budgets.
  • DP-6 (historical data migration) is the safety net: it rescales all stored integers for non-2dp budgets. For correctness, DP-6 must only rescale transactions that were encoded at 2dp, not ones already correctly encoded by this PR's server paths. A % 100 === 0 heuristic is not reliable — round JPY amounts (¥500, ¥1000, ¥10000) are extremely common and would be incorrectly rescaled. The only clean solution is to land DP-2 through DP-6 within the same release so that no 0dp-correct transactions exist in the wild before the migration runs. Reviewers should flag this PR if the release timeline cannot guarantee that.

AI Disclaimer

AI generated (Claude Sonnet 4.6 via Claude Code).

Testing

  • Added unit tests for amountFromYnab covering USD, JPY, IRR/KRW (0dp), and unknown currency fallback (src/server/importers/ynab5.test.ts).
  • Added integration tests for createAccount starting balance encoding for USD (2dp), JPY (0dp), and empty/default currency (src/server/accounts/app.test.ts).
  • Full loot-core test suite passes (874 tests).

Checklist

  • Release notes added (see link above)
  • [!] No obvious regressions in affected areas
  • Self-review has been performed - I have read every line of this diff and can explain what each change does and why it is needed

Bundle Stats

Bundle Files count Total bundle size % Changed
desktop-client 37 13.23 MB → 13.65 MB (+424.1 kB) +3.13%
loot-core 1 4.86 MB → 4.87 MB (+2.36 kB) +0.05%
api 2 3.87 MB → 3.87 MB (+2.29 kB) +0.06%
cli 1 7.97 MB 0%
crdt 1 11.12 kB 0%
View detailed bundle stats

desktop-client

Total

Files count Total bundle size % Changed
37 13.23 MB → 13.65 MB (+424.1 kB) +3.13%
Changeset (largest 100 files by percent change)
File Δ Size
node_modules/@jlongster/sql.js/dist/sql-wasm.js 🆕 +89.79 kB 0 B → 89.79 kB
node_modules/@bufbuild/protobuf/dist/esm/wkt/gen/google/protobuf/descriptor_pb.js 🆕 +45.49 kB 0 B → 45.49 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts 🆕 +24.02 kB 0 B → 24.02 kB
home/runner/work/actual/actual/packages/loot-core/src/server/db/index.ts 🆕 +18.95 kB 0 B → 18.95 kB
node_modules/@bufbuild/protobuf/dist/esm/registry.js 🆕 +18.87 kB 0 B → 18.87 kB
node_modules/adm-zip/adm-zip.js 🆕 +17.33 kB 0 B → 17.33 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sync/index.ts 🆕 +12.81 kB 0 B → 12.81 kB
node_modules/@bufbuild/protobuf/dist/esm/reflect/reflect.js 🆕 +10.45 kB 0 B → 10.45 kB
node_modules/adm-zip/zipEntry.js 🆕 +10.41 kB 0 B → 10.41 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/index.ts 🆕 +9.56 kB 0 B → 9.56 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/envelope.ts 🆕 +8.9 kB 0 B → 8.9 kB
node_modules/adm-zip/zipFile.js 🆕 +8.81 kB 0 B → 8.81 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/base.ts 🆕 +7.88 kB 0 B → 7.88 kB
node_modules/adm-zip/headers/entryHeader.js 🆕 +7.53 kB 0 B → 7.53 kB
node_modules/@bufbuild/protobuf/dist/esm/wire/binary-encoding.js 🆕 +7.41 kB 0 B → 7.41 kB
node_modules/adm-zip/util/utils.js 🆕 +7.16 kB 0 B → 7.16 kB
home/runner/work/actual/actual/packages/loot-core/src/server/budget/tracking.ts 🆕 +6.72 kB 0 B → 6.72 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/executors.ts 🆕 +6.14 kB 0 B → 6.14 kB
node_modules/@bufbuild/protobuf/dist/esm/reflect/reflect-check.js 🆕 +5.72 kB 0 B → 5.72 kB
node_modules/@bufbuild/protobuf/dist/esm/from-binary.js 🆕 +5.09 kB 0 B → 5.09 kB
home/runner/work/actual/actual/packages/crdt/src/crdt/timestamp.ts 🆕 +5.02 kB 0 B → 5.02 kB
node_modules/@bufbuild/protobuf/dist/esm/to-binary.js 🆕 +4.62 kB 0 B → 4.62 kB
node_modules/@bufbuild/protobuf/dist/esm/create.js 🆕 +4.38 kB 0 B → 4.38 kB
node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js 🆕 +4.37 kB 0 B → 4.37 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema-helpers.ts 🆕 +3.91 kB 0 B → 3.91 kB
node_modules/@bufbuild/protobuf/dist/esm/wire/text-format.js 🆕 +3.38 kB 0 B → 3.38 kB
node_modules/adm-zip/methods/zipcrypto.js 🆕 +3.14 kB 0 B → 3.14 kB
node_modules/@bufbuild/protobuf/dist/esm/codegenv2/boot.js 🆕 +2.93 kB 0 B → 2.93 kB
home/runner/work/actual/actual/packages/loot-core/src/server/db/sort.ts 🆕 +2.89 kB 0 B → 2.89 kB
node_modules/murmurhash/murmurhash.js 🆕 +2.86 kB 0 B → 2.86 kB
node_modules/adm-zip/headers/mainHeader.js 🆕 +2.75 kB 0 B → 2.75 kB
home/runner/work/actual/actual/packages/loot-core/src/server/models.ts 🆕 +2.69 kB 0 B → 2.69 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/index.ts 🆕 +2.69 kB 0 B → 2.69 kB
node_modules/@bufbuild/protobuf/dist/esm/proto-int64.js 🆕 +2.59 kB 0 B → 2.59 kB
node_modules/adm-zip/util/errors.js 🆕 +2.47 kB 0 B → 2.47 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sync/encoder.ts 🆕 +2.29 kB 0 B → 2.29 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/path-join.ts 🆕 +2.23 kB 0 B → 2.23 kB
node_modules/@bufbuild/protobuf/dist/esm/reflect/unsafe.js 🆕 +2 kB 0 B → 2 kB
node_modules/adm-zip/util/constants.js 🆕 +1.91 kB 0 B → 1.91 kB
home/runner/work/actual/actual/packages/crdt/src/crdt/merkle.ts 🆕 +1.91 kB 0 B → 1.91 kB
node_modules/@bufbuild/protobuf/dist/esm/wire/base64-encoding.js 🆕 +1.77 kB 0 B → 1.77 kB
node_modules/@bufbuild/protobuf/dist/esm/reflect/guard.js 🆕 +1.65 kB 0 B → 1.65 kB
home/runner/work/actual/actual/packages/loot-core/src/server/aql/exec.ts 🆕 +1.61 kB 0 B → 1.61 kB
home/runner/work/actual/actual/packages/loot-core/src/server/sheet.ts 🆕 +1.56 kB 0 B → 1.56 kB
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/index.ts 🆕 +1.54 kB 0 B → 1.54 kB
node_modules/adm-zip/util/fattr.js 🆕 +1.49 kB 0 B → 1.49 kB
home/runner/work/actual/actual/packages/loot-core/src/server/app.ts 🆕 +1.22 kB 0 B → 1.22 kB
home/runner/work/actual/actual/packages/loot-core/src/server/encryption/encryption-internals.ts 🆕 +1.2 kB 0 B → 1.2 kB
node_modules/adm-zip/methods/inflater.js 🆕 +1.02 kB 0 B → 1.02 kB
home/runner/work/actual/actual/packages/loot-core/src/server/post.ts 🆕 +999 B 0 B → 999 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/unicodeLike.ts 🆕 +995 B 0 B → 995 B
node_modules/@bufbuild/protobuf/dist/esm/descriptors.js 🆕 +918 B 0 B → 918 B
node_modules/adm-zip/methods/deflater.js 🆕 +906 B 0 B → 906 B
home/runner/work/actual/actual/packages/crdt/src/proto/sync_pb.ts 🆕 +895 B 0 B → 895 B
home/runner/work/actual/actual/packages/loot-core/src/server/undo.ts 🆕 +815 B 0 B → 815 B
node_modules/@bufbuild/protobuf/dist/esm/reflect/scalar.js 🆕 +813 B 0 B → 813 B
node_modules/@bufbuild/protobuf/dist/esm/reflect/names.js 🆕 +812 B 0 B → 812 B
home/runner/work/actual/actual/packages/loot-core/src/server/server-config.ts 🆕 +774 B 0 B → 774 B
node_modules/@bufbuild/protobuf/dist/esm/wire/text-encoding.js 🆕 +758 B 0 B → 758 B
home/runner/work/actual/actual/packages/loot-core/src/server/prefs.ts 🆕 +682 B 0 B → 682 B
node_modules/@bufbuild/protobuf/dist/esm/wkt/wrappers.js 🆕 +625 B 0 B → 625 B
node_modules/@bufbuild/protobuf/dist/esm/codegenv2/file.js 🆕 +571 B 0 B → 571 B
node_modules/@bufbuild/protobuf/dist/esm/reflect/nested-types.js 🆕 +543 B 0 B → 543 B
home/runner/work/actual/actual/packages/loot-core/src/server/mutators.ts 🆕 +524 B 0 B → 524 B
node_modules/mitt/dist/mitt.mjs 🆕 +513 B 0 B → 513 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/connection/index.ts 🆕 +512 B 0 B → 512 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/shared.ts 🆕 +498 B 0 B → 498 B
home/runner/work/actual/actual/packages/loot-core/src/server/budget/util.ts 🆕 +403 B 0 B → 403 B
home/runner/work/actual/actual/packages/loot-core/src/server/encryption/index.ts 🆕 +393 B 0 B → 393 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/fetch/index.ts 🆕 +373 B 0 B → 373 B
node_modules/adm-zip/util/index.js 🆕 +358 B 0 B → 358 B
home/runner/work/actual/actual/packages/loot-core/src/server/sync/repair.ts 🆕 +340 B 0 B → 340 B
node_modules/@bufbuild/protobuf/dist/esm/is-message.js 🆕 +320 B 0 B → 320 B
node_modules/@bufbuild/protobuf/dist/esm/codegenv2/restore-json-names.js 🆕 +298 B 0 B → 298 B
node_modules/@bufbuild/protobuf/dist/esm/reflect/error.js 🆕 +278 B 0 B → 278 B
node_modules/adm-zip/util/decoder.js 🆕 +273 B 0 B → 273 B
home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/globals.ts 🆕 +262 B 0 B → 262 B
node_modules/adm-zip/methods/index.js 🆕 +262 B 0 B → 262 B
home/runner/work/actual/actual/packages/loot-core/src/server/aql/index.ts 🆕 +258 B 0 B → 258 B
node_modules/adm-zip/headers/index.js 🆕 +230 B 0 B → 230 B
node_modules/@bufbuild/protobuf/dist/esm/codegenv2/message.js 🆕 +220 B 0 B → 220 B
home/runner/work/actual/actual/packages/loot-core/src/server/db/util.ts 🆕 +195 B 0 B → 195 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/normalise.ts 🆕 +168 B 0 B → 168 B
__vite-browser-external 🆕 +166 B 0 B → 166 B
home/runner/work/actual/actual/packages/loot-core/src/server/main-app.ts 🆕 +149 B 0 B → 149 B
home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/util.ts 🆕 +133 B 0 B → 133 B
home/runner/work/actual/actual/packages/loot-core/src/server/cloud-storage.ts 🆕 +129 B 0 B → 129 B
node_modules/absurd-sql/dist/indexeddb-backend.js 🆕 +99 B 0 B → 99 B
home/runner/work/actual/actual/packages/loot-core/src/server/errors.ts 📈 +412 B (+214.58%) 192 B → 604 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/asyncStorage/index.ts 📈 +706 B (+155.16%) 455 B → 1.13 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/async.ts 📈 +576 B (+146.19%) 394 B → 970 B
home/runner/work/actual/actual/packages/loot-core/src/platform/server/indexeddb/index.ts 📈 +348 B (+25.87%) 1.31 kB → 1.65 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/normalisation.ts 📈 +67 B (+20.36%) 329 B → 396 B
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +417 B (+4.51%) 9.04 kB → 9.45 kB
src/queries/pagedQuery.ts 📈 +132 B (+4.12%) 3.13 kB → 3.26 kB
src/queries/aqlQuery.ts 📈 +4 B (+3.23%) 124 B → 128 B
src/auth/AuthProvider.tsx 📈 +20 B (+1.44%) 1.35 kB → 1.37 kB
src/undo/index.ts 📈 +4 B (+0.73%) 551 B → 555 B
src/tags/queries.ts 📈 +2 B (+0.71%) 282 B → 284 B
node_modules/chevrotain/lib_esm/src/parse/grammar/first.js 📈 +8 B (+0.62%) 1.27 kB → 1.28 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
static/js/Value.js 4.49 MB → 4.9 MB (+425.62 kB) +9.26%
static/js/theme.js 31.01 kB → 31.39 kB (+388 B) +1.22%
static/js/extends.js 473.99 kB → 474.05 kB (+58 B) +0.01%
static/js/client.js 450.92 kB → 450.94 kB (+21 B) +0.00%
static/js/ReportRouter.js 1.25 MB → 1.25 MB (+20 B) +0.00%
static/js/SchedulesTable.js 203.52 kB → 203.54 kB (+20 B) +0.01%

Smaller

Asset File Size % Changed
static/js/index.js 1.58 MB → 1.58 MB (-1.76 kB) -0.11%
static/js/wide.js 298.23 kB → 297.97 kB (-262 B) -0.09%

Unchanged

Asset File Size % Changed
static/js/BackgroundImage.js 121.09 kB 0%
static/js/FormulaEditor.js 814.39 kB 0%
static/js/ManageRules.js 46.47 kB 0%
static/js/PayeeRuleCountLabel.js 7.1 kB 0%
static/js/ScheduleEditForm.js 146.51 kB 0%
static/js/TransactionEdit.js 90.63 kB 0%
static/js/TransactionList.js 82.8 kB 0%
static/js/_baseIsEqual.js 76.76 kB 0%
static/js/ca.js 185.63 kB 0%
static/js/da.js 100.19 kB 0%
static/js/de.js 182.38 kB 0%
static/js/en-GB.js 9.25 kB 0%
static/js/en.js 202.14 kB 0%
static/js/es.js 177.58 kB 0%
static/js/fr.js 177.35 kB 0%
static/js/indexeddb-main-thread-worker-e59fee74.js 13.46 kB 0%
static/js/it.js 163.93 kB 0%
static/js/narrow.js 364.55 kB 0%
static/js/nb-NO.js 147.07 kB 0%
static/js/nl.js 119.71 kB 0%
static/js/pt-BR.js 187.34 kB 0%
static/js/resize-observer.js 18.06 kB 0%
static/js/th.js 173.33 kB 0%
static/js/toString.js 638.95 kB 0%
static/js/uk.js 216.7 kB 0%
static/js/useFormatList.js 2.52 kB 0%
static/js/useTransactionBatchActions.js 9.71 kB 0%
static/js/workbox-window.prod.es5.js 7.33 kB 0%
static/js/zh-Hans.js 116.44 kB 0%

loot-core

Total

Files count Total bundle size % Changed
1 4.86 MB → 4.87 MB (+2.36 kB) +0.05%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/util/currency.ts 🆕 +569 B 0 B → 569 B
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts 📈 +176 B (+6.13%) 2.81 kB → 2.98 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +236 B (+3.58%) 6.43 kB → 6.66 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts 📈 +334 B (+3.47%) 9.4 kB → 9.73 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +156 B (+1.89%) 8.06 kB → 8.21 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts 📈 +411 B (+1.62%) 24.76 kB → 25.16 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts 📈 +102 B (+1.49%) 6.7 kB → 6.8 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts 📈 +270 B (+1.06%) 24.8 kB → 25.06 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts 📈 +92 B (+0.30%) 29.84 kB → 29.93 kB
home/runner/work/actual/actual/packages/loot-core/src/server/api.ts 📈 +70 B (+0.29%) 23.51 kB → 23.58 kB
View detailed bundle breakdown

Added

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

Removed

Asset File Size % Changed
kcab.worker.DhLbg59B.js 4.86 MB → 0 B (-4.86 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
2 3.87 MB → 3.87 MB (+2.29 kB) +0.06%
Changeset
File Δ Size
home/runner/work/actual/actual/packages/loot-core/src/server/util/currency.ts 🆕 +549 B 0 B → 549 B
home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts 📈 +168 B (+5.97%) 2.75 kB → 2.91 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts 📈 +234 B (+3.67%) 6.22 kB → 6.45 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts 📈 +324 B (+3.44%) 9.19 kB → 9.5 kB
home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts 📈 +149 B (+1.91%) 7.6 kB → 7.75 kB
home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts 📈 +406 B (+1.64%) 24.15 kB → 24.55 kB
home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts 📈 +99 B (+1.53%) 6.33 kB → 6.42 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts 📈 +260 B (+1.04%) 24.32 kB → 24.57 kB
home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts 📈 +89 B (+0.30%) 29.3 kB → 29.39 kB
home/runner/work/actual/actual/packages/loot-core/src/server/api.ts 📈 +66 B (+0.28%) 22.89 kB → 22.95 kB
View detailed bundle breakdown

Added
No assets were added

Removed
No assets were removed

Bigger

Asset File Size % Changed
index.js 3.87 MB → 3.87 MB (+2.29 kB) +0.06%

Smaller
No assets were smaller

Unchanged

Asset File Size % Changed
models.js 0 B 0%

cli

Total

Files count Total bundle size % Changed
1 7.97 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.97 MB 0%

crdt

Total

Files count Total bundle size % Changed
1 11.12 kB 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
index.js 11.12 kB 0%

🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/actualbudget/actual/pull/8167 **Author:** [@StephenBrown2](https://github.com/StephenBrown2) **Created:** 6/9/2026 **Status:** 🔄 Open **Base:** `master` ← **Head:** `feat/currency-decimal-server` --- ### 📝 Commits (3) - [`d39ea4d`](https://github.com/actualbudget/actual/commit/d39ea4daab66b1f9359d189fe9472e17f14ee87a) [AI] feat(currencies): decimal-aware amount handling in importers, sync, export, rules, and API - [`0c115dc`](https://github.com/actualbudget/actual/commit/0c115dc9ef174cc8380685157608f2918a7e3f4c) [AI] test(currencies): update nYNAB onboarding e2e for currency symbol - [`9baa004`](https://github.com/actualbudget/actual/commit/9baa004b77600fdd22ee7ee0091004158c65eb6e) [AI] fix(build): shim bare process in browser bundle so e2e can load ### 📊 Changes **14 files changed** (+262 additions, -62 deletions) <details> <summary>View changed files</summary> 📝 `packages/desktop-client/e2e/onboarding.test.ts` (+6 -2) 📝 `packages/desktop-client/vite.config.mts` (+2 -0) ➕ `packages/loot-core/src/server/accounts/app.test.ts` (+54 -0) 📝 `packages/loot-core/src/server/accounts/app.ts` (+4 -2) 📝 `packages/loot-core/src/server/accounts/sync.ts` (+59 -34) 📝 `packages/loot-core/src/server/api.ts` (+12 -4) 📝 `packages/loot-core/src/server/importers/ynab4.ts` (+15 -4) 📝 `packages/loot-core/src/server/importers/ynab5.test.ts` (+31 -0) 📝 `packages/loot-core/src/server/importers/ynab5.ts` (+19 -10) 📝 `packages/loot-core/src/server/rules/action.ts` (+10 -2) 📝 `packages/loot-core/src/server/transactions/export/export-to-csv.ts` (+10 -4) ➕ `packages/loot-core/src/server/util/currency.ts` (+27 -0) 📝 `packages/loot-core/src/shared/util.ts` (+7 -0) ➕ `upcoming-release-notes/currency-decimal-server.md` (+6 -0) </details> ### 📄 Description ## Description Second part of the multi-currency implementation (i.e. [DP-2]). Implements decimal-aware amount encoding through all loot-core server paths so that currencies with non-standard decimal places (e.g. JPY at 0dp, KWD at 3dp) are stored and exported correctly rather than being assumed to be 2dp like USD. **PR stack:** https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc - [DP-1]: Currency metadata and decimal helper functions — [#8064](https://github.com/actualbudget/actual/pull/8064) - **[DP-2]: Server-side decimal-aware amount handling — This PR** - [DP-3]: desktop-client: transaction table and search — TBD - [DP-4]: desktop-client: budget UI components — TBD - [DP-5]: desktop-client: modals, mobile, settings, and E2E — TBD - [DP-6]: Historical data migration for non-2dp currencies — TBD - [DP-7]: desktop-client: remove "hide decimal places" setting — TBD **Changes:** - New `packages/loot-core/src/server/util/currency.ts` — shared helpers (`getDefaultCurrencyCode`, `getDefaultCurrencyCodeSync`, `setDefaultCurrencyCode`) that read/write the `defaultCurrencyCode` preference, replacing duplicated inline queries across server files. - New `integerToCurrencyAmount(integer, code)` in `#shared/util` — symmetric companion to the existing `amountToCurrencyInteger`. - YNAB5 importer: updates `amountFromYnab` to convert milliunits using the budget's currency precision, and sets `defaultCurrencyCode` from the budget's ISO code on import. - YNAB4 importer: uses `amountToCurrencyInteger` with the budget's currency instead of a hardcoded scale. - `accounts/app.ts`, `accounts/sync.ts`, `rules/action.ts`, `transactions/export/export-to-csv.ts`, `api.ts`: all replaced ad-hoc `getDecimalPlaces` + `amountToInteger` patterns with the new shared helpers. No behavior change for existing 2dp budgets (USD, EUR, GBP, etc.). ### Regression analysis for non-2dp budgets Before this PR, all server paths hardcoded 2dp regardless of `defaultCurrencyCode`. The preference existed in the schema and was already exposed in the Settings UI (`Currency.tsx`) for client-side display formatting, but was never read by the server. This PR makes the server read it and apply the correct precision. - **Existing budgets with no currency set**: zero risk. Empty string falls back to 2dp via `getDecimalPlaces`, identical behavior to before. - **Existing budgets with `defaultCurrencyCode = 'JPY'` (or other 0dp currency)**: Historical transactions were stored at 100x inflation by the old server code (¥1234 → integer `123400`). The client masked this by combining 2dp display with the `hideFraction` pref (set automatically to `true` when a 0dp currency is selected in Settings), so ¥1234 stored as `123400` rendered as `1234.00` → `1234` — appearing correct. After this PR, new server writes produce correctly-encoded integers (¥1234 → `1234`). The same client path then renders `1234` as `12.34` → `12` via `hideFraction`, showing 1/100 of the correct value. So display was silently masked before; after this PR it visibly breaks for new transactions until [DP-3] lands. - **Client-side input ([DP-3] not yet landed)**: the transaction entry UI still parses user input with 2dp assumptions. A JPY user typing ¥1234 in the UI will still produce integer `123400` via the client path, even though server-side writes (bank sync, YNAB import) now produce `1234`. [DP-3] is a fast-follow requirement to close this gap. - **Budget templates** (`schedule-template.ts`, `category-template-context.ts`, `budget/actions.ts`): not updated in this PR. Template amounts remain at 2dp while transaction amounts use the correct precision for non-2dp budgets. - **[DP-6]** (historical data migration) is the safety net: it rescales all stored integers for non-2dp budgets. For correctness, [DP-6] must only rescale transactions that were encoded at 2dp, not ones already correctly encoded by this PR's server paths. A `% 100 === 0` heuristic is not reliable — round JPY amounts (¥500, ¥1000, ¥10000) are extremely common and would be incorrectly rescaled. The only clean solution is to land [DP-2] through [DP-6] within the same release so that no 0dp-correct transactions exist in the wild before the migration runs. Reviewers should flag this PR if the release timeline cannot guarantee that. ### AI Disclaimer AI generated (Claude Sonnet 4.6 via Claude Code). ## Related issue(s) <!-- Relates to multi-currency tracking issue --> ## Testing - Added unit tests for `amountFromYnab` covering USD, JPY, IRR/KRW (0dp), and unknown currency fallback (`src/server/importers/ynab5.test.ts`). - Added integration tests for `createAccount` starting balance encoding for USD (2dp), JPY (0dp), and empty/default currency (`src/server/accounts/app.test.ts`). - Full loot-core test suite passes (874 tests). ## Checklist - [x] Release notes added (see link above) - [!] No obvious regressions in affected areas - [x] Self-review has been performed - I have read every line of this diff and can explain what each change does and why it is needed [DP-1]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-1--core-utility-helpers [DP-2]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-2--loot-core-server-decimal-aware-amount-handling [DP-3]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-3--desktop-client-transaction-table-and-search [DP-4]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-4--desktop-client-budget-ui-components [DP-5]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-5--desktop-client-modals-mobile-settings-and-e2e [DP-6]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-6--historical-data-migration-for-non-2dp-budget-currencies [DP-7]: https://gist.github.com/StephenBrown2/a1c3a0cd19f8f2fac0c76c2b93ed20fc#pr-dp-7--remove-hide-decimal-places-setting <!--- actual-bot-sections ---> <hr /> <!--- bundlestats-action-comment key:combined start ---> ### Bundle Stats Bundle | Files count | Total bundle size | % Changed ------ | ----------- | ----------------- | --------- desktop-client | 37 | 13.23 MB → 13.65 MB (+424.1 kB) | +3.13% loot-core | 1 | 4.86 MB → 4.87 MB (+2.36 kB) | +0.05% api | 2 | 3.87 MB → 3.87 MB (+2.29 kB) | +0.06% cli | 1 | 7.97 MB | 0% crdt | 1 | 11.12 kB | 0% <details> <summary>View detailed bundle stats</summary> #### desktop-client **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 37 | 13.23 MB → 13.65 MB (+424.1 kB) | +3.13% <details> <summary>Changeset (largest 100 files by percent change)</summary> File | Δ | Size ---- | - | ---- `node_modules/@jlongster/sql.js/dist/sql-wasm.js` | 🆕 +89.79 kB | 0 B → 89.79 kB `node_modules/@bufbuild/protobuf/dist/esm/wkt/gen/google/protobuf/descriptor_pb.js` | 🆕 +45.49 kB | 0 B → 45.49 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/compiler.ts` | 🆕 +24.02 kB | 0 B → 24.02 kB `home/runner/work/actual/actual/packages/loot-core/src/server/db/index.ts` | 🆕 +18.95 kB | 0 B → 18.95 kB `node_modules/@bufbuild/protobuf/dist/esm/registry.js` | 🆕 +18.87 kB | 0 B → 18.87 kB `node_modules/adm-zip/adm-zip.js` | 🆕 +17.33 kB | 0 B → 17.33 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sync/index.ts` | 🆕 +12.81 kB | 0 B → 12.81 kB `node_modules/@bufbuild/protobuf/dist/esm/reflect/reflect.js` | 🆕 +10.45 kB | 0 B → 10.45 kB `node_modules/adm-zip/zipEntry.js` | 🆕 +10.41 kB | 0 B → 10.41 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/index.ts` | 🆕 +9.56 kB | 0 B → 9.56 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/envelope.ts` | 🆕 +8.9 kB | 0 B → 8.9 kB `node_modules/adm-zip/zipFile.js` | 🆕 +8.81 kB | 0 B → 8.81 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/base.ts` | 🆕 +7.88 kB | 0 B → 7.88 kB `node_modules/adm-zip/headers/entryHeader.js` | 🆕 +7.53 kB | 0 B → 7.53 kB `node_modules/@bufbuild/protobuf/dist/esm/wire/binary-encoding.js` | 🆕 +7.41 kB | 0 B → 7.41 kB `node_modules/adm-zip/util/utils.js` | 🆕 +7.16 kB | 0 B → 7.16 kB `home/runner/work/actual/actual/packages/loot-core/src/server/budget/tracking.ts` | 🆕 +6.72 kB | 0 B → 6.72 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema/executors.ts` | 🆕 +6.14 kB | 0 B → 6.14 kB `node_modules/@bufbuild/protobuf/dist/esm/reflect/reflect-check.js` | 🆕 +5.72 kB | 0 B → 5.72 kB `node_modules/@bufbuild/protobuf/dist/esm/from-binary.js` | 🆕 +5.09 kB | 0 B → 5.09 kB `home/runner/work/actual/actual/packages/crdt/src/crdt/timestamp.ts` | 🆕 +5.02 kB | 0 B → 5.02 kB `node_modules/@bufbuild/protobuf/dist/esm/to-binary.js` | 🆕 +4.62 kB | 0 B → 4.62 kB `node_modules/@bufbuild/protobuf/dist/esm/create.js` | 🆕 +4.38 kB | 0 B → 4.38 kB `node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js` | 🆕 +4.37 kB | 0 B → 4.37 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/schema-helpers.ts` | 🆕 +3.91 kB | 0 B → 3.91 kB `node_modules/@bufbuild/protobuf/dist/esm/wire/text-format.js` | 🆕 +3.38 kB | 0 B → 3.38 kB `node_modules/adm-zip/methods/zipcrypto.js` | 🆕 +3.14 kB | 0 B → 3.14 kB `node_modules/@bufbuild/protobuf/dist/esm/codegenv2/boot.js` | 🆕 +2.93 kB | 0 B → 2.93 kB `home/runner/work/actual/actual/packages/loot-core/src/server/db/sort.ts` | 🆕 +2.89 kB | 0 B → 2.89 kB `node_modules/murmurhash/murmurhash.js` | 🆕 +2.86 kB | 0 B → 2.86 kB `node_modules/adm-zip/headers/mainHeader.js` | 🆕 +2.75 kB | 0 B → 2.75 kB `home/runner/work/actual/actual/packages/loot-core/src/server/models.ts` | 🆕 +2.69 kB | 0 B → 2.69 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/index.ts` | 🆕 +2.69 kB | 0 B → 2.69 kB `node_modules/@bufbuild/protobuf/dist/esm/proto-int64.js` | 🆕 +2.59 kB | 0 B → 2.59 kB `node_modules/adm-zip/util/errors.js` | 🆕 +2.47 kB | 0 B → 2.47 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sync/encoder.ts` | 🆕 +2.29 kB | 0 B → 2.29 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/path-join.ts` | 🆕 +2.23 kB | 0 B → 2.23 kB `node_modules/@bufbuild/protobuf/dist/esm/reflect/unsafe.js` | 🆕 +2 kB | 0 B → 2 kB `node_modules/adm-zip/util/constants.js` | 🆕 +1.91 kB | 0 B → 1.91 kB `home/runner/work/actual/actual/packages/crdt/src/crdt/merkle.ts` | 🆕 +1.91 kB | 0 B → 1.91 kB `node_modules/@bufbuild/protobuf/dist/esm/wire/base64-encoding.js` | 🆕 +1.77 kB | 0 B → 1.77 kB `node_modules/@bufbuild/protobuf/dist/esm/reflect/guard.js` | 🆕 +1.65 kB | 0 B → 1.65 kB `home/runner/work/actual/actual/packages/loot-core/src/server/aql/exec.ts` | 🆕 +1.61 kB | 0 B → 1.61 kB `home/runner/work/actual/actual/packages/loot-core/src/server/sheet.ts` | 🆕 +1.56 kB | 0 B → 1.56 kB `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/index.ts` | 🆕 +1.54 kB | 0 B → 1.54 kB `node_modules/adm-zip/util/fattr.js` | 🆕 +1.49 kB | 0 B → 1.49 kB `home/runner/work/actual/actual/packages/loot-core/src/server/app.ts` | 🆕 +1.22 kB | 0 B → 1.22 kB `home/runner/work/actual/actual/packages/loot-core/src/server/encryption/encryption-internals.ts` | 🆕 +1.2 kB | 0 B → 1.2 kB `node_modules/adm-zip/methods/inflater.js` | 🆕 +1.02 kB | 0 B → 1.02 kB `home/runner/work/actual/actual/packages/loot-core/src/server/post.ts` | 🆕 +999 B | 0 B → 999 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/unicodeLike.ts` | 🆕 +995 B | 0 B → 995 B `node_modules/@bufbuild/protobuf/dist/esm/descriptors.js` | 🆕 +918 B | 0 B → 918 B `node_modules/adm-zip/methods/deflater.js` | 🆕 +906 B | 0 B → 906 B `home/runner/work/actual/actual/packages/crdt/src/proto/sync_pb.ts` | 🆕 +895 B | 0 B → 895 B `home/runner/work/actual/actual/packages/loot-core/src/server/undo.ts` | 🆕 +815 B | 0 B → 815 B `node_modules/@bufbuild/protobuf/dist/esm/reflect/scalar.js` | 🆕 +813 B | 0 B → 813 B `node_modules/@bufbuild/protobuf/dist/esm/reflect/names.js` | 🆕 +812 B | 0 B → 812 B `home/runner/work/actual/actual/packages/loot-core/src/server/server-config.ts` | 🆕 +774 B | 0 B → 774 B `node_modules/@bufbuild/protobuf/dist/esm/wire/text-encoding.js` | 🆕 +758 B | 0 B → 758 B `home/runner/work/actual/actual/packages/loot-core/src/server/prefs.ts` | 🆕 +682 B | 0 B → 682 B `node_modules/@bufbuild/protobuf/dist/esm/wkt/wrappers.js` | 🆕 +625 B | 0 B → 625 B `node_modules/@bufbuild/protobuf/dist/esm/codegenv2/file.js` | 🆕 +571 B | 0 B → 571 B `node_modules/@bufbuild/protobuf/dist/esm/reflect/nested-types.js` | 🆕 +543 B | 0 B → 543 B `home/runner/work/actual/actual/packages/loot-core/src/server/mutators.ts` | 🆕 +524 B | 0 B → 524 B `node_modules/mitt/dist/mitt.mjs` | 🆕 +513 B | 0 B → 513 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/connection/index.ts` | 🆕 +512 B | 0 B → 512 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fs/shared.ts` | 🆕 +498 B | 0 B → 498 B `home/runner/work/actual/actual/packages/loot-core/src/server/budget/util.ts` | 🆕 +403 B | 0 B → 403 B `home/runner/work/actual/actual/packages/loot-core/src/server/encryption/index.ts` | 🆕 +393 B | 0 B → 393 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/fetch/index.ts` | 🆕 +373 B | 0 B → 373 B `node_modules/adm-zip/util/index.js` | 🆕 +358 B | 0 B → 358 B `home/runner/work/actual/actual/packages/loot-core/src/server/sync/repair.ts` | 🆕 +340 B | 0 B → 340 B `node_modules/@bufbuild/protobuf/dist/esm/is-message.js` | 🆕 +320 B | 0 B → 320 B `node_modules/@bufbuild/protobuf/dist/esm/codegenv2/restore-json-names.js` | 🆕 +298 B | 0 B → 298 B `node_modules/@bufbuild/protobuf/dist/esm/reflect/error.js` | 🆕 +278 B | 0 B → 278 B `node_modules/adm-zip/util/decoder.js` | 🆕 +273 B | 0 B → 273 B `home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/globals.ts` | 🆕 +262 B | 0 B → 262 B `node_modules/adm-zip/methods/index.js` | 🆕 +262 B | 0 B → 262 B `home/runner/work/actual/actual/packages/loot-core/src/server/aql/index.ts` | 🆕 +258 B | 0 B → 258 B `node_modules/adm-zip/headers/index.js` | 🆕 +230 B | 0 B → 230 B `node_modules/@bufbuild/protobuf/dist/esm/codegenv2/message.js` | 🆕 +220 B | 0 B → 220 B `home/runner/work/actual/actual/packages/loot-core/src/server/db/util.ts` | 🆕 +195 B | 0 B → 195 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/sqlite/normalise.ts` | 🆕 +168 B | 0 B → 168 B `__vite-browser-external` | 🆕 +166 B | 0 B → 166 B `home/runner/work/actual/actual/packages/loot-core/src/server/main-app.ts` | 🆕 +149 B | 0 B → 149 B `home/runner/work/actual/actual/packages/loot-core/src/server/spreadsheet/util.ts` | 🆕 +133 B | 0 B → 133 B `home/runner/work/actual/actual/packages/loot-core/src/server/cloud-storage.ts` | 🆕 +129 B | 0 B → 129 B `node_modules/absurd-sql/dist/indexeddb-backend.js` | 🆕 +99 B | 0 B → 99 B `home/runner/work/actual/actual/packages/loot-core/src/server/errors.ts` | 📈 +412 B (+214.58%) | 192 B → 604 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/asyncStorage/index.ts` | 📈 +706 B (+155.16%) | 455 B → 1.13 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/async.ts` | 📈 +576 B (+146.19%) | 394 B → 970 B `home/runner/work/actual/actual/packages/loot-core/src/platform/server/indexeddb/index.ts` | 📈 +348 B (+25.87%) | 1.31 kB → 1.65 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/normalisation.ts` | 📈 +67 B (+20.36%) | 329 B → 396 B `home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts` | 📈 +417 B (+4.51%) | 9.04 kB → 9.45 kB `src/queries/pagedQuery.ts` | 📈 +132 B (+4.12%) | 3.13 kB → 3.26 kB `src/queries/aqlQuery.ts` | 📈 +4 B (+3.23%) | 124 B → 128 B `src/auth/AuthProvider.tsx` | 📈 +20 B (+1.44%) | 1.35 kB → 1.37 kB `src/undo/index.ts` | 📈 +4 B (+0.73%) | 551 B → 555 B `src/tags/queries.ts` | 📈 +2 B (+0.71%) | 282 B → 284 B `node_modules/chevrotain/lib_esm/src/parse/grammar/first.js` | 📈 +8 B (+0.62%) | 1.27 kB → 1.28 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- static/js/Value.js | 4.49 MB → 4.9 MB (+425.62 kB) | +9.26% static/js/theme.js | 31.01 kB → 31.39 kB (+388 B) | +1.22% static/js/extends.js | 473.99 kB → 474.05 kB (+58 B) | +0.01% static/js/client.js | 450.92 kB → 450.94 kB (+21 B) | +0.00% static/js/ReportRouter.js | 1.25 MB → 1.25 MB (+20 B) | +0.00% static/js/SchedulesTable.js | 203.52 kB → 203.54 kB (+20 B) | +0.01% **Smaller** Asset | File Size | % Changed ----- | --------- | --------- static/js/index.js | 1.58 MB → 1.58 MB (-1.76 kB) | -0.11% static/js/wide.js | 298.23 kB → 297.97 kB (-262 B) | -0.09% **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- static/js/BackgroundImage.js | 121.09 kB | 0% static/js/FormulaEditor.js | 814.39 kB | 0% static/js/ManageRules.js | 46.47 kB | 0% static/js/PayeeRuleCountLabel.js | 7.1 kB | 0% static/js/ScheduleEditForm.js | 146.51 kB | 0% static/js/TransactionEdit.js | 90.63 kB | 0% static/js/TransactionList.js | 82.8 kB | 0% static/js/_baseIsEqual.js | 76.76 kB | 0% static/js/ca.js | 185.63 kB | 0% static/js/da.js | 100.19 kB | 0% static/js/de.js | 182.38 kB | 0% static/js/en-GB.js | 9.25 kB | 0% static/js/en.js | 202.14 kB | 0% static/js/es.js | 177.58 kB | 0% static/js/fr.js | 177.35 kB | 0% static/js/indexeddb-main-thread-worker-e59fee74.js | 13.46 kB | 0% static/js/it.js | 163.93 kB | 0% static/js/narrow.js | 364.55 kB | 0% static/js/nb-NO.js | 147.07 kB | 0% static/js/nl.js | 119.71 kB | 0% static/js/pt-BR.js | 187.34 kB | 0% static/js/resize-observer.js | 18.06 kB | 0% static/js/th.js | 173.33 kB | 0% static/js/toString.js | 638.95 kB | 0% static/js/uk.js | 216.7 kB | 0% static/js/useFormatList.js | 2.52 kB | 0% static/js/useTransactionBatchActions.js | 9.71 kB | 0% static/js/workbox-window.prod.es5.js | 7.33 kB | 0% static/js/zh-Hans.js | 116.44 kB | 0% </div> </details> --- #### loot-core **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 4.86 MB → 4.87 MB (+2.36 kB) | +0.05% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/util/currency.ts` | 🆕 +569 B | 0 B → 569 B `home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts` | 📈 +176 B (+6.13%) | 2.81 kB → 2.98 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts` | 📈 +236 B (+3.58%) | 6.43 kB → 6.66 kB `home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts` | 📈 +334 B (+3.47%) | 9.4 kB → 9.73 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts` | 📈 +156 B (+1.89%) | 8.06 kB → 8.21 kB `home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts` | 📈 +411 B (+1.62%) | 24.76 kB → 25.16 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts` | 📈 +102 B (+1.49%) | 6.7 kB → 6.8 kB `home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts` | 📈 +270 B (+1.06%) | 24.8 kB → 25.06 kB `home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts` | 📈 +92 B (+0.30%) | 29.84 kB → 29.93 kB `home/runner/work/actual/actual/packages/loot-core/src/server/api.ts` | 📈 +70 B (+0.29%) | 23.51 kB → 23.58 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.bNRRO4re.js | 0 B → 4.87 MB (+4.87 MB) | - **Removed** Asset | File Size | % Changed ----- | --------- | --------- kcab.worker.DhLbg59B.js | 4.86 MB → 0 B (-4.86 MB) | -100% **Bigger** No assets were bigger **Smaller** No assets were smaller **Unchanged** No assets were unchanged </div> </details> --- #### api **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 2 | 3.87 MB → 3.87 MB (+2.29 kB) | +0.06% <details> <summary>Changeset</summary> File | Δ | Size ---- | - | ---- `home/runner/work/actual/actual/packages/loot-core/src/server/util/currency.ts` | 🆕 +549 B | 0 B → 549 B `home/runner/work/actual/actual/packages/loot-core/src/server/transactions/export/export-to-csv.ts` | 📈 +168 B (+5.97%) | 2.75 kB → 2.91 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/util.ts` | 📈 +234 B (+3.67%) | 6.22 kB → 6.45 kB `home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab4.ts` | 📈 +324 B (+3.44%) | 9.19 kB → 9.5 kB `home/runner/work/actual/actual/packages/loot-core/src/server/rules/action.ts` | 📈 +149 B (+1.91%) | 7.6 kB → 7.75 kB `home/runner/work/actual/actual/packages/loot-core/src/server/importers/ynab5.ts` | 📈 +406 B (+1.64%) | 24.15 kB → 24.55 kB `home/runner/work/actual/actual/packages/loot-core/src/shared/currencies.ts` | 📈 +99 B (+1.53%) | 6.33 kB → 6.42 kB `home/runner/work/actual/actual/packages/loot-core/src/server/accounts/sync.ts` | 📈 +260 B (+1.04%) | 24.32 kB → 24.57 kB `home/runner/work/actual/actual/packages/loot-core/src/server/accounts/app.ts` | 📈 +89 B (+0.30%) | 29.3 kB → 29.39 kB `home/runner/work/actual/actual/packages/loot-core/src/server/api.ts` | 📈 +66 B (+0.28%) | 22.89 kB → 22.95 kB </details> <details> <summary>View detailed bundle breakdown</summary> <div> **Added** No assets were added **Removed** No assets were removed **Bigger** Asset | File Size | % Changed ----- | --------- | --------- index.js | 3.87 MB → 3.87 MB (+2.29 kB) | +0.06% **Smaller** No assets were smaller **Unchanged** Asset | File Size | % Changed ----- | --------- | --------- models.js | 0 B | 0% </div> </details> --- #### cli **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 7.97 MB | 0% <details> <summary>View detailed bundle breakdown</summary> <div> **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.97 MB | 0% </div> </details> --- #### crdt **Total** Files count | Total bundle size | % Changed ----------- | ----------------- | --------- 1 | 11.12 kB | 0% <details> <summary>View detailed bundle breakdown</summary> <div> **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 ----- | --------- | --------- index.js | 11.12 kB | 0% </div> </details> </details> <!--- bundlestats-action-comment key:combined end ---> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-06-11 21:13:27 -05:00
GiteaMirror changed title from [PR #8167] [WIP] [AI] feat(currencies): decimal-aware amount handling in server to [PR #8167] [AI] feat(currencies): decimal-aware amount handling in server 2026-06-14 06:36:19 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/actual#122380