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
Account.displayed_exchange_currency holds the account/currency precedence for transactions, and shown_exchange_currency() expresses the same rule as a query expression for the insights and account totals, replacing the per-module checks.
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
- Amounts default to the linked transaction's amount when left empty
- Linked transactions must be in the strategy's payment/target currency; pickers only search those
- Allow setting entities on transactions created from an entry
- Fix crash when only the expense transaction was linked
Holdings under a year annualized their rate before turning it back into
the period return, so a few days with a modest gain (+1.3% in one day is
~10,600% a year) fell outside xirr's search range and showed no percentage.
Solve the rate over the period held instead.
- Shared header (date, description, badges); each side gets its own row:
account with its category, tags and entities, amount + exchanged amount
- Timeline rail from the transfer icon branching into the out/in icons
- Amounts drop below on small screens and sit bottom-right on lg, like
regular items; spacing matches regular item metadata rows
- Notes move below the legs on transfers so they don't sit in the rail
- One hero number with a single return line; secondary totals behind a Details toggle
- Holdings in one list card with quiet group subheaders, value and %/yr per row
- Group holdings by account group or asset class, remembered in the session
- Detail page: value and chart up top, Your position and home-currency sidebar
- Replace tooltips with visible text; keep amounts from wrapping on phones
- Unit-priced accounts now honour their income categories, tags and entities:
a matching transaction is a gain or loss, and any other unlinked one is money
in or out at that day's market price. Before, every unlinked outflow was a
loss and yields were booked as new money in.
- A transfer out of an account tracked by value counts its own amount. It used
the other side converted at the day's rate, so a coin bought from a savings
account moved the coin's price change onto the savings account.
AccountSerializer assigned the many-to-many fields with setattr, which Django rejects, so any write that included them returned a 500. The default ModelSerializer create/update already handles them.
Investments landed without demo data. The ETF, Bitcoin and savings accounts become investments, and new accounts cover the rest of the tracker: Apple shares (dividends paid into checking, a partial sale, gifted shares with an estimated cost), a retirement fund tracked by value (quarterly gains and a loss, a yearly fee) and gold. Asset classes have targets that add up to 100%, plus one without a target to show how rebalancing leaves it out.
The investment examples use their own random seed, so the rest of the demo is unchanged. The demo test now renders the investment pages and checks each kind of holding has figures.
Account names on a combined transfer were cut at a fixed 14rem even when the row had room. On large screens the row now stays on one line and the account side can grow up to half of it, so names only truncate past that.
The transfer form had no entities field and always created paid transfers. Each side now has its own entities, shown as from -> to in the list like category and tags, and a Projected/Paid toggle applies to both sides.
Editing a transfer also offered only active categories, tags and entities and non-archived accounts, so saving silently dropped a deactivated tag or failed on an archived account. The transfer's own items stay selectable, as in the transaction form.