Beancount 2.3.5代码未生成复式记账文件,如何修改实现生成?
Beancount 2.3.5生成分类账文件及过账交易的解决方案
问题描述
我正在使用Beancount 2.3.5,尝试编写一个概念验证文件,实现以下功能:
- 创建简单的会计科目表
- 通过复式记账法将样本交易过账到分类账中
以下是我的代码:
from datetime import datetime from decimal import Decimal as D import beancount.core.data as data line_number = 42 metadata = data.new_metadata(filename='./myfile.beancount', lineno=line_number) # define accounts accounts = ["Assets:Bank", "Expenses:Groceries"] # create postings posting1 = data.Posting(accounts[0], data.Amount(D('1000'), 'USD'), None, None, None, meta=metadata) posting2 = data.Posting(accounts[1], data.Amount(D('200'), 'USD'), None, None, None, meta=metadata) # create transactions transaction1 = data.Transaction( meta = metadata, date = datetime.strptime("2022-03-29", '%Y-%m-%d'), flag = "*", payee = "Bob's Grocery Store", narration = "Groceries for the week", tags = set(), links = set(), postings = [posting1, posting2] )
运行代码后,期望生成新的myfile.beancount文件,其中包含上述交易,但实际并未生成任何文件。怀疑需要先将账户标记为已开户,但找不到合适的操作入口,请问如何修改代码以生成文件并正确将交易过账到文件中?
修改方案
你的代码仅在内存中创建了交易对象,缺少序列化到文本文件的步骤,同时确实需要先添加账户开户指令(Beancount要求所有使用的账户必须先完成开户)。以下是完整的修改代码及说明:
修改后的完整代码
from datetime import datetime from decimal import Decimal as D import beancount.core.data as data import beancount.core.printer as printer # 初始化元数据 filename = './myfile.beancount' line_number = 1 metadata = data.new_metadata(filename=filename, lineno=line_number) # 定义账户列表 accounts = ["Assets:Bank", "Expenses:Groceries"] account_currency = 'USD' open_date = datetime.strptime("2022-01-01", '%Y-%m-%d').date() # 创建账户开户条目 open_entries = [] for account in accounts: open_meta = data.new_metadata(filename, line_number) open_entry = data.Open( meta=open_meta, date=open_date, account=account, currencies={account_currency}, booking=None ) open_entries.append(open_entry) line_number += 1 # 创建交易的posting(注意金额需符合复式记账平衡:总额为0) # 买 groceries 是银行账户减少200USD,费用增加200USD posting_meta = data.new_metadata(filename, line_number) posting1 = data.Posting( account=accounts[0], amount=data.Amount(D('-200'), 'USD'), cost=None, price=None, flag=None, meta=posting_meta ) line_number += 1 posting_meta2 = data.new_metadata(filename, line_number) posting2 = data.Posting( account=accounts[1], amount=data.Amount(D('200'), 'USD'), cost=None, price=None, flag=None, meta=posting_meta2 ) line_number += 1 # 创建交易条目 transaction_meta = data.new_metadata(filename, line_number) transaction1 = data.Transaction( meta=transaction_meta, date=datetime.strptime("2022-03-29", '%Y-%m-%d').date(), flag="*", payee="Bob's Grocery Store", narration="Groceries for the week", tags=set(), links=set(), postings=[posting1, posting2] ) # 合并所有条目(开户+交易) all_entries = open_entries + [transaction1] # 将条目序列化为Beancount格式文本 beancount_text = printer.print_entries(all_entries) # 写入文件 with open(filename, 'w', encoding='utf-8') as f: f.write(beancount_text)
关键修改说明
- 添加账户开户条目:
使用data.Open创建每个账户的开户记录,指定账户名、支持的币种和开户日期,这是Beancount的必填要求。 - 修复交易金额平衡:
原代码中交易的金额总和不为0(1000+200=1200),不符合复式记账规则。修改为银行账户减少200USD(负金额)、费用账户增加200USD(正金额),确保总额为0。 - 序列化与文件写入:
导入beancount.core.printer模块,使用printer.print_entries()将内存中的条目转换为标准Beancount格式的文本,再通过Python文件操作写入目标文件。 - 元数据行号管理:
逐步递增行号,让生成的文件中每个条目都有正确的元数据行号,便于后续调试。
生成的myfile.beancount内容示例
2022-01-01 open Assets:Bank USD 2022-01-01 open Expenses:Groceries USD 2022-03-29 * "Bob's Grocery Store" "Groceries for the week" Assets:Bank -200.00 USD Expenses:Groceries 200.00 USD
内容的提问来源于stack exchange,提问作者Homunculus Reticulli
相关产品推荐
相关产品推荐

