In this release invoicing learned the three shapes money actually takes: an agreement that bills every period, a total split into instalments the client agreed to, and debt closed by a deduction rather than a payment. There is a catalog to pick lines from instead of typing them, and a workspace can keep its books in a timezone of its own. On the fixes side, CSV import reads thousands separators, an OFX file whose bank reuses one FITID keeps every row, editing a tracked holding no longer wipes its cost basis, and a user with reconciliation history can be deleted.
Features
- Recurring invoices. An agreement with a client emits one invoice per period, for a retainer, a plan or anything subscription-shaped, with the price kept as dated terms: a change applies from the first period starting on or after its date, and nothing is prorated. The page shows what each agreement bills per month, what is still to come, and every period written so far; one written by hand can be linked to the period it belongs to (#988)
- Instalments. "3x", or "half upfront, half on delivery": the schedule the client agreed to, as rows that add up to the total. The invoice's due date becomes the last of them, so every list and filter keeps its meaning, and settled money covers the schedule first to last (#1021)
- Deductions. Tax withheld by the client, a gateway fee, an exchange difference: debt closed without money arriving. The balance and the state move, what was received does not, so the ledger and the bank still agree (#1021)
- A catalog to invoice from. Products and services with their own prices, so a line is picked instead of typed. Optional at every level: a workspace with no catalog writes lines exactly as before, an invoice mixes catalog and free lines, and a price can still be changed on the spot (#1014)
- A timezone per instance and per workspace. An admin sets the application timezone that decides which day "today" is for balances, budgets, due dates and scheduled work; a workspace can then keep its own, so one server can hold books closed in Sao Paulo and in Tokyo. Closes #209, by @domgjntoki (#909) ๐, with the workspace layer on top (#1010)
- Add a transaction from anywhere. A + next to Transactions in the sidebar, and an Add Transaction button on the account page with that account and its currency already chosen. Closes #861 and #992 (#1006)
- Create a category or a person without leaving the form. When a search matches nothing, the picker offers to create it and selects it in place, in the transaction dialog, the rule dialog and the import review. Closes #847 and #677 (#1007)
- Filter the list to transfers. A Transfer option in the Type filter, counting both a linked pair and a category marked as a transfer. Closes #883, by @jorishaenseler15 (#1009) ๐
- Jump to the other side of a transfer from the transaction dialog. Closes #882, by @jorishaenseler15 (#1005) ๐
- Status as a rule condition. A rule can match Pending or Posted, in the preview, in nested groups and through the MCP tools. Closes #938 (#1004)
Fixes
- CSV import misread thousands separators. A lone comma was always a decimal point, so
25,000came in as 25.00, any currency symbol other thanR$failed the row, and the type column was matched case sensitively. The separator is now inferred per column from all of its values. Closes #665 (#1008) - An OFX file lost rows when the bank reused a FITID. Some banks give several entries on one day the same id, and everything after the first was taken for a duplicate. The key now includes the amount and the type, and re-importing the same file still skips every row. Closes #911 (#998)
- Editing a tracked holding wiped its cost basis. Even renaming one sent an empty purchase price, so the holding lost its return until the ledger was replayed. Closes #965 (#999)
- Import history showed the wrong currency. A EUR statement imported into a USD workspace had its totals printed in dollars. Closes #881, by @jorishaenseler15 (#1003) ๐
- "% of portfolio" was empty for holdings in your own currency. Closes #980 (#994)
- A user with reconciliation history could not be deleted. The three columns that record who answered a suggestion, wrote a rule or appears in the history had no delete action, so the constraint refused. The rows belong to the workspace, so they stay and only the reference is cleared. By @ADolkun (#1024) ๐
- Enable Banking refused to connect at some banks. The first fetch asked for 91 days where the bank allows 90, and since it runs during connect, the connection could never be added. Closes #655 (#996)
- Agent chat failed with Anthropic. Current Claude models reject
temperature, which the provider was still sending. Closes #542 (#997) - A bank sync could reuse the wrong ids. A name collision inside the per-account loop overwrote the set of account ids built before it. By @ADolkun (#1023) ๐
- A shared credit line was counted twice in the net worth tooltip, where the sidebar and the backend already counted it once. By @ADolkun (#1025) ๐
- The dashboard drill-down closed when you edited a transaction in it, because the dialog it opens lives outside the panel. Closes #989 (#1001)
- The balance chart did not say what it was comparing. It is Balance Evolution now, with the legend to match. Closes #688 (#1000)
- Connection status badges and a handful of labels bypassed translation. Closes #583 and #879 (#1002)
Under the hood
Migrations 092 to 096 run automatically on upgrade: three new tables for schedules, the catalog and instalments, two nullable columns, and the delete action on the reconciliation references; nothing existing is rewritten ยท CI moved to native uv, runs the seven PostgreSQL report scenarios that used to be skipped, and picks its suites from what a PR touches, closes #820, by @ADolkun (#870) ๐ ยท a deduction test was pinned to the clock and started failing on a date that had nothing to do with it (#1031)
Thanks @ADolkun, @domgjntoki and @jorishaenseler15 for the code and the reviews, and @abdalanervoso-debug, @olokotoh, @pintoryan, @olwi572, @remusache, @turkelali, @jn73, @panga, @henriqueberlesi, @vhsantos26, @A1kyy, @Zolli, @N8-Yue, @8hnd2g9xs2-sys and @jzimath-lab for the reports ๐
Full Changelog: v0.16.1...v0.16.2