将外部数据半自动导入beancount。
项目描述
Beancount-import是一个工具,用于从外部数据源半自动地将财务数据导入到Beancount记账系统中,以及合并和核对导入的交易与彼此以及现有交易。
主要功能
-
可插拔的数据源架构,包括对现有的OFX(现金、投资和退休账户)、Mint.com、Amazon.com和Venmo的支持。
-
支持beancount导入器,因此编写自己的导入器更容易,现有的beancount和fava用户可以轻松切换。
-
强有力地关联导入的交易与源数据,以自动避免重复。
-
基于学习分类器(目前基于决策树)自动预测导入交易中未知部分。
-
复杂的交易匹配/合并系统,可以半自动地将来自独立来源的手动输入和导入的交易进行合并和核对。
-
易于使用、功能强大的基于Web的用户界面。
基本操作
从数据源模块中,beancount-import获取一个待处理的导入交易列表。(也可能提供平衡和价格条目。)根据外部数据源,待处理交易可能完全指定所有Beancount账户(例如,来自OFX源的股票投资交易,使用同一投资账户中的现金购买股票),或者可能对未知账户有某些分录,由特殊的账户名称Expenses:FIXME
表示。例如,从银行账户/信用卡账户数据(例如,使用Mint.com数据源)获取的待处理交易始终有两个分录,一个是对应于获取数据的银行账户的已知Beancount账户,另一个是对未知账户的分录。
对于每笔待处理交易,beancount-import会尝试找到与现有交易以及其他待处理交易匹配的交易,并计算出一组候选合并交易。对于每个未知账户分录,Beancount-import会根据学到的分类器预测账户。通过网页界面,用户可以查看待处理交易,选择原始交易或合并候选交易之一,并确认或修改任何预测的账户。网页界面会显示每个候选交易将添加或删除的日记账中的行。一旦用户接受候选交易,该候选交易将被插入或合并到Beancount日记账中,然后用户将看到下一个待处理条目。
导入的交易包括元数据字段,这些字段位于交易和分录中,具有多种用途:
- 指示数据源模块哪些外部表示已导入且不应再次导入的条目;
- 指示哪些分录已被清账,意味着它们已被权威来源确认,这也限制了匹配(已清账的分录只能与未清账的分录匹配);
- 提供训练用于预测未知账户的分类器所需的信息;
- 提供可能有助于识别和理解交易的信息。
安装
-
如果需要,请确保已激活合适的Python 3虚拟环境。
-
要从PyPi安装最新发布的包,只需键入:
pip install beancount-import
或者,要从仓库克隆中安装,键入:
pip install .
或者对于开发:
pip install -e .
发布的PyPI包包括预构建的前端副本,不需要进一步构建。当从git仓库安装时,前端会由上述安装命令自动构建,但需要Node.js。如果您尚未安装,请遵循前端目录中的说明进行安装。
演示
要查看Beancount-import在测试数据上的实际效果,请参阅examples目录中的说明。
数据源
数据源通过实现由beancount_import.source模块定义的Source接口来定义。
数据源提供了一种导入和核对已下载数据的方法。要自动检索财务数据,可以使用finance_dl包。您还可以使用任何其他机制,包括从金融机构网站手动下载数据,前提是它符合数据源所需的格式。
目前支持的数据源集合包括:
- beancount_import.source.ofx:最通用的数据源,支持支票、储蓄、信用卡、投资和退休账户。
- beancount_import.source.mint:支持Mint.com上支持的所有现金账户类型。
- beancount_import.source.venmo
- beancount_import.source.amazon:支持常规和数字订单发票。
- beancount_import.source.healthequity:支持HealthEquity.com的HSA账户,包括现金和投资交易。
- beancount_import.source.google_purchases:导入Google从Gmail消息中启发式提取的购买。
- beancount_import.source.paypal:导入Paypal交易。
- beancount_import.source.waveapps:从Wave(一个免费的收据扫描网站/移动应用程序)导入收据。
- beancount_import.source.stockplanconnect:从摩根士丹利股票计划连接导入发布/交易交易。
- beancount_import.source.schwab_csv:从施瓦布经纪账户导入交易和头寸CSV导出。
- beancount_import.source.ultipro_google:导入谷歌员工Ultipro工资单。
- beancount_import.source.generic_importer_source:从
beancount.ingest.importer.ImporterProtocol
子类导入器导入。有关如何编写一个导入器和查看示例目录(简单的csv导入器)的示例,请参阅beancount的文档。
有关配置的详细信息,请参阅各个数据源文档。
使用方法
要运行Beancount导入,创建一个调用beancount_import.webserver.main
函数的Python脚本。请参阅示例fresh和手动输入。
错误
无论是Beancount本身还是数据源引起的错误,都会在错误
选项卡中显示。在继续之前,通常最好手动解决任何错误,无论是使用内置编辑器还是外部编辑器,因为某些错误可能导致行为不正确。然而,平衡错误通常可以忽略。
查看候选人
选择候选人
选项卡以查看当前待处理的导入条目,以及与现有和其他待处理交易的所有建议匹配。原始未匹配的条目始终列在最后,包含最多匹配分录的建议列在最前面。顶部带有复选框的列表指示每个建议匹配中使用了哪些现有或待处理交易;当前待处理交易始终列在第一位。如果找到许多不正确的匹配,可以取消选中复选框以过滤匹配。
可以通过单击它或使用上下箭头键选择其中一个建议条目。要接受建议条目而不更改,可以按Enter键或双击它。这立即修改了日记账以反映更改,并在日记账选项卡中显示相关的日记账部分,以便您可以轻松进行手动编辑。
指定未知账户
如果建议条目包含未知账户,它们将以独特的背景颜色突出显示,并标记为组号。显示的账户是自动预测的账户,如果没有自动预测(例如,由于缺乏训练数据),则标记为费用:FIXME
。有几种方法可以纠正任何不正确的账户预测
- 要更改单个账户,可以Shift+单击它,输入新账户名称,然后按Enter键。如果在输入账户名称时按Escape键,则账户将保持不变。用于自动完成的模糊匹配算法:例如,如果您输入"ex:co",则将匹配任何具有以下子序列的账户:第一个组件以(不区分大小写)"ex"开头,第二个组件以"co"开头,例如
费用:饮料:咖啡
账户。 - 要更改建议条目中具有相同组号的账户,可以不按Shift键单击其中一个账户,或按对应组号的数字键。一旦输入账户并按Enter键,则指定的账户将替换组中的所有分录。
- 要更改建议条目中的所有账户,可以单击
更改账户
按钮或按键。一旦输入账户并按Enter键,则指定的账户将替换当前条目中的所有未知账户。 - 如果您希望推迟指定正确的账户,您可以点击
Fixme later
按钮,或者按f
键。这将用原始未知账户名称替换当前条目中所有未知账户的名称。如果您接受这个条目,包括这些 FIXME 账户的交易将被添加到您的账簿中,下次您启动 Beancount-import 时,该交易将被视为待处理条目。
查看关联的源数据
数据源可能表明某些候选条目与额外的源数据相关联,通常基于交易中包含的元数据字段和/或链接。例如,beancount_import.source.amazon
数据源将订单发票 HTML 页面与交易关联,而 beancount_import.source.google_purchases
数据源将购买详情 HTML 页面关联。其他可能的源数据类型包括 PDF 对账单和收据图片。
您可以通过选择 源数据
选项卡来查看当前选定的候选条目的任何关联源数据。
更改叙述、收款人或标签
要修改条目的叙述,您可以单击它,点击 叙述
按钮,或者按 n
键。这实际上允许您修改收款人、链接和标签。如果您在交易的第一个句子中引入了语法错误,文本框将突出显示为红色,并且焦点将保持直到您修正它或按 Escape,这会将交易的第一个句子恢复到其先前值。
检查未清算的过账
未清算
选项卡显示具有权威来源且未清算的账户过账列表。通常,通过添加适当的源特定元数据字段来标记过账为已清算,这些字段将其与外部数据表示关联,例如在 OFX 源的情况下,添加 ofx_fitid
字段。
此列表可能有助于查找需要手动纠正的差异。未清算过账的典型原因包括
- 过账的源数据尚未下载。
- 该交易是已存在于账簿中的另一笔交易的重复,需要手动合并/删除。
- 过账是在导入源数据的最早日期之前,并且没有更早的数据。可以通过向账户或其祖先账户的
open
指令添加cleared_before: <日期>
元数据字段来忽略此类过账。 - 源数据缺失或无法导入,但过账已手动验证。可以通过向它们添加
cleared: TRUE
元数据字段来忽略此类过账。
跳过和忽略导入的条目
如果您遇到一个您不想导入的待处理条目,您有几个选项
-
您可以通过在
待处理
选项卡中选择不同的交易来跳过它,或者通过单击标有⏩
的按钮或按]
键来跳到下一个待处理条目。这将在此会话中跳过它,但它仍然作为待处理条目,如果您重新启动 beancount-import,它将再次被包括在内。 -
您可以通过单击标有
Fixme later
的按钮或按f
键来重置所有未知账户,然后接受候选条目。这将把交易添加到您的账簿中,但未知账户留为费用:FIXME
。这对于您不知道如何分配账户的交易或您预计将与尚未下载的数据生成的另一笔交易匹配的交易很有用。下一次您启动 beancount-import 时,带有费用:FIXME
账户的交易将被包含在待处理条目列表的末尾。 -
您可以点击标记为
忽略
的按钮,或者按i
键,将选定的候选人添加到特殊的“忽略”期刊文件中。这对于错误交易很有用,例如实际重复的交易。如果您重新启动 beancount-import,将不会再次显示被忽略的条目。但是,如果您手动从“忽略”期刊文件中删除它们,它们将作为待定条目返回。
与反向代理一起使用
如果您想使用 Beancount-import 的 TLS 或身份验证等功能,则可以运行它后面的反向代理提供此功能。例如,以下 NGINX 位置配置可以路由流量到本地 Beancount-import 实例:
location /some/url/prefix/ {
proxy_pass_header Server;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Scheme $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://localhost:8101/;
}
将 /some/url/prefix/
替换为您所需的 URL 路径(保留末尾斜杠),或者甚至直接使用 /
使 Beancount-import 可在 URL 根目录中访问。
与现有的 Beancount 期刊一起使用
如果您开始使用包含在数据源外部数据中引用的交易的现有 beancount 期刊,数据源将不知道跳过这些交易,因为它们不会有必要的元数据来指示关联。因此,它们都将作为新的待定导入交易显示给您。
然而,匹配机制很可能已经确定与现有交易的正确匹配,这将被作为默认选项显示。接受这些匹配将仅仅是将相关元数据插入您的期刊的效果,使交易被视为“已结清”并将在您下次运行 Beancount-import 时不再导入。即使是大量交易,这个过程也应该相对较快。
开发
对于此包的开发,请确保使用 pip install -e .
命令安装 Beancount-import,而不是使用 pip install .
命令。如果您以前在没有 -e
选项的情况下运行了 pip install
命令,您可以简单地重新运行 pip install -e .
命令。
测试
您可以使用 pytest
命令运行测试。
许多测试是“黄金”测试,它们通过创建某种状态的文本表示并与 testdata/ 目录中特定文件的包含内容进行比较来工作。如果您更改了这些测试之一或添加了一个新的测试,您可以通过设置环境变量 BEANCOUNT_IMPORT_GENERATE_GOLDEN_TESTDATA=1
来使测试自动生成输出,例如:
BEANCOUNT_IMPORT_GENERATE_GOLDEN_TESTDATA=1 pytest
在设置此环境变量之前,请确保至少提交您对相关 testdata
文件所做的任何更改。这样,您可以使用 git diff
手动验证现有输出与新输出之间的任何更改。
Web 前端
Web 前端源代码位于 frontend/ 目录中。有关在更改后重建和运行前端的信息,请参阅该目录中的 README.md 文件。
基本工作流程
Mint.com 数据源中的简单支出交易
假设用户于 2016-08-09 使用信用卡在星巴克购买咖啡,并已将 Mint.com 设置为检索此信用卡的交易数据。
给定以下 CSV 条目
"Date","Description","Original Description","Amount","Transaction Type","Category","Account Name","Labels","Notes"
"8/10/2016","Starbucks","STARBUCKS STORE 12345","2.45","debit","Coffee Shops","My Credit Card","",""
和以下开放账户指令
1900-01-01 open Liabilities:Credit-Card USD
mint_id: "My Credit Card"
Mint 数据源将生成以下待定交易
2016-08-10 * "STARBUCKS STORE 12345"
Liabilities:Credit-Card -2.45 USD
date: 2016-08-10
source_desc: "STARBUCKS STORE 12345"
Expenses:FIXME 2.45 USD
用户可能手动指定未知账户为 Expenses:Coffee
。然后,Web 界面将显示更新后的更改集
+2016-08-10 * "STARBUCKS STORE 12345"
+ Liabilities:Credit-Card -2.45 USD
+ date: 2016-08-10
+ source_desc: "STARBUCKS STORE 12345"
+ Expenses:Coffee 2.45 USD
如果 Expenses:Coffee
账户尚不存在,Beancount-import 将在更改集中还包括一个 open
指令
+2016-08-10 * "STARBUCKS STORE 12345"
+ Liabilities:Credit-Card -2.45 USD
+ date: 2016-08-10
+ source_desc: "STARBUCKS STORE 12345"
+ Expenses:Coffee 2.45 USD
+ 2016-08-10 open Expenses:Coffee USD
一旦用户接受此更改,更改集将被应用到账本中。存在 date
和 source_desc
元数据字段表示 Mint 数据源已经清除了 Liabilities:Credit-Card
的记账。在 source_desc
中出现的单词,以及 Liabilities:Credit-Card
的 来源 账户和 Expenses:Coffee
的 目标 账户的组合,作为分类器的训练示例。包含单词 STARBUCKS
的后续挂起交易很可能会自动分类为 Expenses:Coffee
。请注意,尽管在这种情况下,叙述与 source_desc
字段匹配,但叙述对自动预测没有影响。用户不得删除或修改这些元数据字段,但可以添加额外的元数据字段。
Mint.com 有自己的启发式方法,从金融机构提供的 Original Description
计算出 Description
和 Category
字段。然而,Mint 数据源会忽略这些字段,因为它们不稳定(如果重新下载数据可能会改变)且不太可靠。
匹配手动输入的交易
考虑上一个示例中显示的相同交易,假设在运行导入之前,用户已经手动输入了该交易
2016-08-09 * "Coffee"
Liabilities:Credit-Card -2.45 USD
Expenses:Coffee
运行 Beancount-import 时,用户将看到两个候选交易
2016-08-09 * "Coffee"
Liabilities:Credit-Card -2.45 USD
+ date: 2016-08-10
+ source_desc: "STARBUCKS STORE 12345"
Expenses:Coffee
+2016-08-10 * "STARBUCKS STORE 12345"
+ Liabilities:Credit-Card -2.45 USD
+ date: 2016-08-10
+ source_desc: "STARBUCKS STORE 12345"
+ Expenses:FIXME 2.45 USD
用户应选择第一个;选择第二个会导致重复的交易(但稍后可以诊断为一个未清账交易)。第二个候选中的 Expenses:FIXME
账户通常实际上是某个其他、可能不正确的预测账户,但被清楚地标记为可以更改的预测。
通常情况下,手动输入的交易上的日期(可能是交易实际发生的日期)并不完全与银行提供的日期相同。为了处理这种差异,Beancount-import 允许匹配相差最多 5 天的记账。即使整体交易日期不同,date
元数据字段也允许可靠地将记账与 CSV 文件中的相应条目匹配。
请注意,尽管此交易是手动输入的,但一旦与挂起交易匹配,并且添加了 source_desc
和 date
元数据字段,它作为训练示例的功能与上一个示例完全相同。
信用卡付款交易
假设用户使用银行账户支付信用卡余额,并且 Mint.com 已设置从银行账户和信用卡中检索交易。
给定以下 CSV 条目
"Date","Description","Original Description","Amount","Transaction Type","Category","Account Name","Labels","Notes"
"11/27/2013","Transfer from My Checking","CR CARD PAYMENT ALEXANDRIA VA","66.88","credit","Credit Card Payment","My Credit Card","",""
"12/02/2013","National Federal Des","NATIONAL FEDERAL DES:TRNSFR","66.88","debit","Transfer","My Checking","",""
以及以下开放账户指令
1900-01-01 open Liabilities:Credit-Card USD
mint_id: "My Credit Card"
1900-01-01 open Assets:Checking USD
mint_id: "My Checking"
Mint 数据源将生成 2 个挂起交易,并对于第一个交易将提供两个候选交易
+2013-11-27 * "CR CARD PAYMENT ALEXANDRIA VA"
+ Liabilities:Credit-Card 66.88 USD
+ date: 2013-11-27
+ source_desc: "CR CARD PAYMENT ALEXANDRIA VA"
+ Assets:Checking -66.88 USD
+ date: 2013-12-02
+ source_desc: "NATIONAL FEDERAL DES:TRNSFR"
+2013-11-27 * "CR CARD PAYMENT ALEXANDRIA VA"
+ Liabilities:Credit-Card 66.88 USD
+ date: 2013-11-27
+ source_desc: "CR CARD PAYMENT ALEXANDRIA VA"
+ Expenses:FIXME -66.88 USD
请注意,第二个交易中的 Expenses:FIXME
账户实际上是自动预测的账户。如果以前有类似的交易,它很可能会被正确预测为 Assets:Checking
。
用户应接受第一个候选以同时导入这两个交易。在这种情况下,这两个记账都被视为已清账,并且新交易将产生两个训练示例,对应于每个 source_desc
、来源账户和目标账户的组合。
但是,如果用户接受第二个候选(可能是因为交易尚未记入支票账户,并且从支票账户数据派生的挂起交易尚不可用),并且要么将账户保留为 Expenses:FIXME
,手动指定 Assets:Checking
,或者依赖自动预测选择 Assets:Checking
,那么在从支票账户导入交易时,用户将看到以下候选,并将有另一个机会接受匹配。
2013-11-27 * "CR CARD PAYMENT ALEXANDRIA VA"
Liabilities:Credit-Card 66.88 USD
date: 2013-11-27
source_desc: "CR CARD PAYMENT ALEXANDRIA VA"
Assets:Checking -66.88 USD
+ date: 2013-12-02
+ source_desc: "NATIONAL FEDERAL DES:TRNSFR"
+2013-12-02 * "NATIONAL FEDERAL DES:TRNSFR"
+ Assets:Checking -66.88 USD
+ date: 2013-12-02
+ source_desc: "NATIONAL FEDERAL DES:TRNSFR"
+ Expenses:FIXME 66.88 USD
许可
版权所有 (C) 2014-2018 Jeremy Maitin-Shepard。
仅在 GNU 通用公共许可证第 2.0 版下分发。有关详细信息,请参阅 LICENSE 文件。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。
源代码分发
构建分发
beancount_import-1.4.0-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 64935357e839946fc8d0a618f761e0db4939a5417420e114d887f3f20644bab7 |
|
MD5 | 3aafea9e8d89d719970cb3513c377000 |
|
BLAKE2b-256 | ff8d1bd8bfd0db3a85829ca392f8e348ef8256ddc73a2f671c821381e0d3780a |