Consolidated rows are collapsible and remember their state per currency in localStorage. Share percentages render as badges on a shared subgrid column so they line up regardless of amount width. Currency and account menus drop their extra padding to align with the card title.
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.
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.