An import run can now be given an account, and every transaction it
creates goes into that account instead of the one the profile maps. This
lets a single profile serve several accounts at the same bank, for
statements that only name the account in a header cell or not at all,
instead of keeping one copy of the profile per account.
- ImportRun gets an optional `account` (SET_NULL), shown on the run card.
- The upload form offers the user's active accounts when the profile
imports transactions, and leaves the field out for profiles that import
accounts, currencies, categories, tags or entities.
- CSV and Excel rows take the run's account before deduplication, so
rules comparing `account` check against the picked account. The
profile's account mapping is skipped for these rows.
- QIF files use the run's account instead of the account named after the
file.
- The import API accepts an optional `account_id`, limited to accounts
the user can access, rejected for profiles that don't import
transactions, and returns `account` on import runs.
Leaving the account empty keeps the current behaviour.
Closes#538
A consolidated total on the Net Worth page was a single number: it said
what everything is worth in one currency, but not how much of it each
currency makes up, which is what you want to know when you hold the same
money in several currencies (or in currencies standing for gold, stocks
or crypto).
calculate_currency_totals now keeps, next to each consolidated total, the
components it was built from: the currency's own total and the exchanged
total of every currency that exchanges into it, all in the consolidated
currency. calculate_consolidated_shares gives each of them its share of
the total as a percentage, drops the ones that add nothing and sorts the
rest from largest to smallest. Shares are taken over the absolute total,
so a currency that adds to it always has a positive share and one that
takes from it (debt) a negative one; with a zero total there's no share.
Currencies that hide their exchanged amounts still show up, since they
still count towards the consolidated total, and so do exchange targets
that only exist through the deep search.
On the Net Worth page, each Consolidated row now lists its components
with their share and amount in the consolidated currency. Clicking one
shows that currency's line on the charts, like the currency rows above.
Currencies and accounts get a "Show exchanged amounts" switch, on by
default. Turning it off hides the amounts converted to the exchange
currency without removing the exchange currency, so consolidated totals
on the Net Worth page keep working.
The switch belongs to whichever one provides the exchange currency:
- Transactions (including both legs of combined transfers) use the
account's switch when the account has its own exchange currency, and
the currency's switch otherwise, matching how the exchanged amount is
picked.
- Account cards and Net Worth account rows follow the account.
- Currency cards, the monthly summary and daily allowance, Net Worth
currency rows and the month-by-month and year-by-year insights follow
the currency.
Currency totals still convert hidden currencies, because the
consolidated totals are built from those values; the setting only
leaves them out of the displayed data. The API keeps returning
exchanged_amount for transactions, and the account serializer exposes
the new field (currencies already serialize all fields).
Closes#486
Import uploads were always written to /usr/src/app/temp, presets were
read from /usr/src/app/import_presets and the caches lived in /var/tmp,
so WYGIWYH only worked from the Docker image's layout. Running it as a
systemd service with a strict sandbox, or on an immutable distro like
NixOS, needs these folders to follow the app or be configurable.
- Presets are read from IMPORT_PRESETS_ROOT, the import_presets folder
next to the app.
- Uploads wait in IMPORT_TEMP_ROOT, the temp folder next to the app by
default, and movable with the IMPORT_TEMP_ROOT env var. The web views,
the API and the import service all use it.
- The file-based caches live under CACHE_ROOT, /var/tmp by default, and
movable with the CACHE_ROOT env var.
In the Docker image the app sits in /usr/src/app, so every default
resolves to the same folder as before.
The import service checked that a file was inside the temp folder with a
plain string prefix, which also accepted sibling folders such as
/usr/src/app/temp-other. It now compares paths.
CI no longer needs to create /usr/src/app before running the tests.
Fixes#472
On touch devices AirDatepicker opens pickers in mobile mode, which closes
them through a shared overlay rather than on blur. The library keeps that
overlay in its module scope, inside a global container appended to the
body. Boosted navigation swaps the body, so the container and overlay are
removed: the library notices the missing container and builds a new one
for the next picker, but keeps reusing the detached overlay. From then on
nothing receives the outside click, and an open picker stays on screen
over the form until the page is fully reloaded.
Create every picker through a helper that remembers the overlay and moves
it back into the current global container whenever it was left detached.
Fixes#227