跳到主要内容

记账

目的

为什么要记账?

  • 有多少钱、在哪儿: 清楚自己的资产负债余额情况
  • 钱从哪儿来、到哪儿去: 清楚自己的收入支出情况
  • 预算计划 Budget

内容

记哪些东西?

  • 资产 Assets
    • Cash
    • Bank
    • UnionPay(DebitCard)
    • AliPay
    • WeChatPay
    • ApplePay
    • Investment
    • Receivable
  • 负债 Liabilities
    • CreditCard
    • Payable
  • 收入 Revenues/Income
    • Salary
    • Gift
  • 支出 Expenses
    • 三餐饮食 Food & Dining
    • 家居日用 Household & Daily Essentials
    • 交通出行 Transportation
    • 通讯数码 Telecom & Digital
    • 医疗健康 Medical & Health
    • 教育学习 Education & Learning
    • 社交娱乐 Social & Entertainment
    • 服饰美妆 Wear & Beauty
    • 金融财税 Financial & Tax
    • 其他杂项 Misc
  • 权益 Equity
    • Rounding
    • Conversion

方法

单式和复式记账法

[!NOTE] 会计等式

  • 资产 = 负债 + 所有者权益
  • 收入 - 费用 = 利润
  • 资产 = 负债 + (所有者权益 + 收入 - 费用)

Revenues/Income

-

Expenses

+

Assets

+

Liabilities

-

Equity

-

[!note]+ 复式记账
每条记录至少包括两个账户: 借(Debit+)、贷(Credit-). 账户、分类本质上都是科目.
理论上需要多条记录相互验证, 实际操作多数情况可以只录一条, 另一条自动生成.

[!NOTE]- 举例

  • 转账: 资产- -> 资产+
  • 还款: 资产- -> 负债+
  • 支出: 资产- -> 支出+
  • 负债支出: 负债- -> 支出+
  • 借入: 负债- -> 资产+
  • 还款: 资产- -> 负债+
  • 借出: 资产- -> 资产+
  • 收款: 资产- -> 资产+

表与字段设计

  • 交易明细表
    • 日期 Date
    • 描述 Payee|Description
    • 金额 Amount %% price * quantity %% %% 对应支付账户(减少), 即始终为负值, 计算余额累加即可 %%
    • 来源账户 From %% 关联到账户表的 Name (排除支出) %%
    • 去向账户 To %% 关联到账户表的 Name %%
  • 账户科目表
    • 名称 Name
    • 类型 Type: 资产、负债、收入、支出、权益
    • 结余 Balance SUMIF(交易表!$C$2:$C$1000, A2, 交易表!$E$2:$E$1000) + (-1)*SUMIF(交易表!$D$2:$D$1000, A2, 交易表!$E$2:$E$1000)

分类与统计

工具

实践

结合 todo 的简易记账方法

title: 结合 todo 的简易记账方法
collapse: true
- 日期作为标题
- 按收款方分组, 若分类需要也可进一步划分
- 注意不要重复记录, 比如可以用 `:` 的方式备注金额
- 字段: Payee|Desc 描述, Amount 金额, From 转出账户, To 转入账户/科目
import re
from decimal import Decimal

def markdown_to_hledger(md_content):
entries = []
current_date = None
account_cache = set()

for line in md_content.split('\n'):
line = line.strip()

# 解析日期标题
date_match = re.match(r'^##\s+(\d{4}-\d{2}-\d{2})', line)
if date_match:
current_date = date_match.group(1)
continue

# 解析所有层级的条目
entry_match = re.match(r'^\s*-\s+\[[ x]\]\s*(.+?)\s*$', line)
if current_date and entry_match:
parts = [p.strip() for p in entry_match.group(1).split('|')]
if len(parts) < 4 or not all(parts[:4]):
continue # 跳过不完整条目

name, amount_str, source, dest = parts[:4]

try:
amount = Decimal(amount_str)
except:
continue # 跳过金额无效条目

# 构建账户名称并缓存
source_acc = f"Assets:{source}"
dest_acc = f"Expenses:{dest}"
account_cache.update([source_acc, dest_acc])

# 生成hledger条目
entry = [
f"{current_date} {name}",
f" {dest_acc:<24} {amount:.2f} CNY",
f" {source_acc}"
]
entries.append('\n'.join(entry))

# 添加账户声明
accounts = '\n'.join([f"account {acc}" for acc in sorted(account_cache)])
return f"{accounts}\n\n" + '\n\n'.join(entries)

参考