预算
张记账的预算遵循 YNAB(You Need A Budget)的信封模型:为一个支出类别创建预算,每月给它分配资金,并把支出账户关联到它。这些账户上的支出就是预算的已支出金额,剩下的部分结转到下个月。预算与账户相互独立:它们从不改变账户的余额。
YYYY-MM-DD budget <Name> <Commodity>YYYY-MM-DD budget-add <Name> <Number> <Commodity>YYYY-MM-DD budget-transfer <FromName> <ToName> <Number> <Commodity>YYYY-MM-DD budget-close <Name>| 指令 | 作用 |
|---|---|
budget |
创建预算 <Name>,以 <Commodity> 计。 |
budget-add |
在其日期所在的月份给预算分配一笔金额。负数金额表示收回资金。 |
budget-transfer |
在其日期所在的月份,把已分配的金额从一个预算转到另一个预算。 |
budget-close |
从其日期所在的月份起关闭预算。 |
预算名称是一个不含空格、引号、冒号、括号或逗号的单词,例如 Food 或 Daily-Groceries。每条指令都需要日期,可以附带一天中的时刻,下方可以写元数据行。
budget 指令读取两个元数据键:
| 键 | 作用 |
|---|---|
alias |
预算在网页界面中的显示名称。 |
category |
预算页面把这个预算列在哪个分组下。 |
账户通过其 open 指令的 budget 元数据计入某个预算。重复这个键可以把账户关联到多个预算。记账行计入其日期当时生效的账户 open 所指的预算,所以账户关闭后用其他 budget 元数据重新开启,从重新开启起计入新的预算。
YYYY-MM-DD open <Account> budget: <Name>2024-01-01 budget Food CNY alias: "Food and groceries" category: "Daily"2024-01-01 budget Fun CNY category: "Discretionary"
2024-01-01 open Assets:Bank:Checking CNY2024-01-01 open Expenses:Groceries CNY budget: Food2024-01-01 open Expenses:Restaurants CNY budget: Food2024-01-01 open Expenses:Movies CNY budget: Fun
2024-01-01 budget-add Food 2000 CNY2024-01-01 budget-add Fun 300 CNY
2024-01-12 * "Supermarket" "weekly shopping" Assets:Bank:Checking -420.00 CNY Expenses:Groceries
2024-01-20 budget-transfer Fun Food 100 CNY1 月,Food 已分配 2100 CNY,已支出 420 CNY,可用 1680 CNY;Fun 可用 200 CNY。
预算按月计算。对每个预算和每个月,张记账记录:
- 已分配(assigned):
budget-add和budget-transfer放入预算的金额,加上上个月月末的可用金额; - 已支出(activity):当月记到关联账户的记账行。支出账户上的花费使它增加,退款使它减少;
- 可用(available):已分配减去已支出。到下个月月初,它成为下个月的已分配金额,所以剩余或超支的金额都会结转。
一些细节:
- 预算从其
budget指令的日期起存在。在这个日期之前记到关联账户的记账行不计入预算,并报告一次BudgetDoesNotExist。 budget-add和budget-transfer的金额以及记账行,会用账本中的价格按各自的日期换算为预算的商品。没有价格可以换算的金额不计入。budget-close从其日期所在的月份起关闭预算:预算页面在这个月及之后的月份把它显示为已关闭,总览页面的预算卡片从那时起不再显示它。之后的budget-close不会再改变什么。之后的指令和记账行仍然计入它。- 网页界面的预算页面显示每个预算在某个月的已分配、已支出和可用金额,以及某个预算在某个月的事件。在查询中,
#budgets和#budget_events包含同样的数据;见张记账特有的表。
| 错误 | 触发条件 |
|---|---|
DefineDuplicatedBudget |
budget 指令指定的预算已经存在。第二条指令会被忽略。 |
BudgetDoesNotExist |
budget-add、budget-transfer 或 budget-close 指定的预算在其日期未定义;这条指令会被忽略。或者记账行的账户关联到在记账行日期未定义的预算;这种情况对每个账户和预算报告一次,交易仍会记账。 |
Beancount 兼容性
Section titled “Beancount 兼容性”Beancount 没有预算指令。在 Beancount 文件中,把它们写成 Beancount 本身接受的 custom 指令:类型加引号,预算名加引号,budget 的货币加引号,budget-add 和 budget-transfer 的金额直接写:
| 张记账 | Beancount 文件 |
|---|---|
2024-01-01 budget Food CNY |
2024-01-01 custom "budget" "Food" "CNY" |
2024-01-01 budget-add Food 2000 CNY |
2024-01-01 custom "budget-add" "Food" 2000 CNY |
2024-01-20 budget-transfer Fun Food 100 CNY |
2024-01-20 custom "budget-transfer" "Fun" "Food" 100 CNY |
2024-12-31 budget-close Food |
2024-12-31 custom "budget-close" "Food" |
元数据行照常跟在后面。bean-check 和 Fava 把这些行当作普通的 custom 条目接受;张记账把它们读作预算,也以这种方式把预算写入 Beancount 文件。早期版本的张记账写出的不加引号的写法 custom budget Food CNY 仍然可以读取,现有账本不受影响,但 Beancount 会拒绝它(Invalid token):如果你还用 bean-check 检查账本,请改用加引号的写法。带有其他值的 custom "budget",例如 Fava 自己的预算条目(custom "budget" Expenses:Coffee "daily" 4.00 EUR),仍然是普通的 custom 指令。
