SMB 发票 + 簿记
一条杂乱消息 → 发票、支出记录以及下一份催款草稿。 无需账户、无需订阅、无锁定——你的资金,存储在你拥有的文件中。
小企业失败的原因不在于工作本身,而在于等待: 大约 55% 的北美 B2B 发票被延迟支付(Atradius,引自 Crestmont Capital,2026 年更新),美国小企业在 2026 年第二季度平均等待 29.3 天才收到付款,比到期日晚约 9 天(Xero 小企业洞察,引自 Foundrly,2026 年 8 月),82% 的小企业倒闭可归因于现金流问题(美国商会,引自 Crestmont,2026 年)。收款概率随时间快速下降——在积极跟进的第一个月内超过 95%,超过 120 天后降至 20–30%(Crestmont,2026 年)。开出发票是容易的部分,追款才是真正的产品——而其他地方的追款功能都被付费墙阻隔:自动提醒是 Wave(19 美元/月)和 Invoice Ninja(14 美元/月)的 Pro 版专属功能(供应商定价页面,2026 年 11 月),Wave 无法向美国/加拿大以外发送发票(Wave 支持,2026 年 9 月 8 日),Zoho Invoice 的免费版每年限制 500 张发票并在 180 天后删除闲置数据(zoho.com/invoice/pricing,读取于 2026-11-11)。此技能免费为你起草追款信。
版本 0.2.0。 根据 v0.1.0 对抗性审查(发现 20 个缺口,全部修复或记录在
MEASUREMENTS.md§11 中)和深度研究修正(research-notes-v2.md§1)重建。变更内容见CHANGELOG.md。以下数据基于捆绑的样本数据实际运行得出,非估算值。
非法律、税务或财务建议。 此技能帮助你创建发票和跟踪资金。税率、注册门槛和发票要求因国家而异且会随时间变化。请自行设定税率,并咨询当地税务机关(在孟加拉国:国家税务局,nbr.gov.bd)或合格会计师以确认适用于你业务的规则。此免责声明也会打印在每张生成的发票和收据的页脚中——孟加拉语文档上使用孟加拉语。关于其背后的记录保存规则(保存内容、发票上的 TIN/BIN、Mushak 表格、保存期限),请参考配套文档:OpenAccountants 的
bd-bookkeeping技能(openaccountants/openaccountants,484★,更新于 2026-11-11)——一本英文参考指南,明确声明“仅作一般参考……未针对任何特定个人的事实进行审查”。它不生成发票。此技能生成发票。
运行它
python3 scripts/bookkeeper.py <command>
Python ≥ 3.9,仅使用标准库。无需安装步骤、无依赖项、无网络调用、无 API 密钥、无账户。数据存储在你可随时打开、复制和迁移的纯 JSON 文件中。
货币规则——在信任任何数字前请阅读
这些规则确保总计准确,这些规则在 v0.1.0 审查中发现此技能曾违反过:
- 货币舍入为半数向上取整(
ROUND_HALF_UP),如同店主使用计算器那样——绝不使用银行家舍入法。৳2.345 为 ৳2.35。 - 数量精确,绝不作为货币舍入。 数量 1.005 即为 1.005;只有行总计进行舍入。数量打印时不显示末尾零(如 3,而非 3.00)。
- 税费按行计算,基于折扣后金额——每行税费在该行上进行半数向上取整后求和(Wave / Xero / FreshBooks 的做法)。3 行 ৳0.35 加 15% 税费为 ৳0.15,而非 ৳0.16。
- 付款状态来源于余额,而非状态字符串。 一张标记为“已付”但仍欠 ৳4,000 的发票报告欠款 ৳4,000,报表会显示状态错误。状态只是提示;逾期状态基于到期日和余额推导得出。
- 货币绝不做跨币种求和。 混合币种的分类账报告各币种总计(৳5,000 + $100),并拒绝合并总计及合并净额——此技能不具备外汇功能并明确说明。
- 分类账问题会明确报错并以 exit 2 退出。
overdue和cashflow命令在遇到行跳过(无效数据)、数字重复、标记为“已付”的发票仍有余额、付款超额、或付款缺少paid_date时,会以 exit 2 退出。报表仍会打印;退出码表示在信任分类账前需先修复它。 - 负数货币先打印减号:−৳4,100——统一约定,处处如此。
工作流:一个输入 → 发票 → 收据 → 催款 → 现金流
1. 从一条 JSON 输入生成发票、报价单或收据
python3 scripts/bookkeeper.py invoice --input samples/invoice-input.json --out out/invoice.html --config config/bd.json
python3 scripts/bookkeeper.py invoice --input samples/invoice-input-bn.json --out out/invoice-bn.html --config config/bd.json --lang bn
python3 scripts/bookkeeper.py invoice --input my-quote.json --out out/quote.html --format md
python3 scripts/bookkeeper.py receipt --input samples/invoice-input.json --out out/receipt.html --paid-date 2026-11-05 --amount-paid 4500
- 输入是一个小型 JSON 文件:业务方 + 客户 + 行项目(描述、数量、单价)+ 发票编号 + 开票日期 + 到期日。具体结构请参见
samples/invoice-input.json。 - 报价单 → 发票 → 收据是同一个生命周期,同一个数据模型。
type: "quote"需要valid_until而非到期日;发票需要具体的日历到期日,而非仅“Net 30”;收据由已付发票生成,使用--paid-date和--amount-paid参数,若付款部分未付清,则显示剩余 বাকি (余额)。金额为 0 的收据会被拒绝——收据确认已收到款项。报价单从不显示已付/余额行(提案上无人欠款),无论是 HTML 还是 Markdown 格式,其编号标记为“报价单编号”而非“发票编号”。 - 发票携带每张发票必需的字段(研究笔记 §3.1):词语“发票”、唯一顺序编号、开票日期、到期日、卖方详情、买方详情、具体描述、行项目、独立一行显示的税费、付款说明 + 应付总额。当存在报价单编号时,报价单编号会在发票上引用;客户 PO 编号和卖方的 税务登记编号(tax_id — 在孟加拉国,为 13 位数字的 BIN) 在提供时打印在发票上。
- 编号是顺序的(
INV-2026-001、INV-2026-002、……)。绝不可跳过或重复使用编号——遗漏或重复在报税时看起来像是缺失的收入或虚构的支出。分类账命令在遇到重复编号时会发出警告并以 exit 2 退出。配置中的numbering_prefix会与发票编号进行核对(发出警告,而非错误);default_terms在输入未提供时填充“条款”行。 - 输出为干净的 HTML(可在浏览器中打开,打印为 PDF)或 Markdown(
--format md)。HTML 中不包含外部资源,因此打印效果与所见一致——已交付的样本是在无头 Chromium 中渲染并打印为 PDF 的(见MEASUREMENTS.md§11.6,截图在docs/目录中)。 - 货币使用
Decimal计算,绝不使用浮点数。折扣是子总计的百分比,逐行应用;税费基于折扣后金额逐行计算(见“货币规则”)。 - 验证严格,输入错误时退出码为 2:缺少到期日、负数数量或价格、税率超出 0–100%、无效日期、格式错误的 JSON、文件缺失、到期日早于开票日、付款日期早于开票日。允许零项目发票(总计 ৳0)但打印警告——这是草稿,并非需隐藏的错误。超额付款会在两份文档命令上打印警告(收据绝不应显示“余额:৳-825”)。
2. 税费——一个你需要手动键入的设置,绝非硬编码税率
# 在发票输入中(这是税率存在的唯一位置):
"tax": {"name": "VAT", "rate_percent": 15}
- 没有工具硬编码税率,此技能同样不这样做。 每个开票工具(Zoho、FreshBooks、Wave、Xero——研究笔记 §5.1)都允许用户定义具名税种 + 百分比,逐行应用,并作为单独一行显示。此技能完全复制该做法:税费是输入中的一个具名税种 + 税率百分比,默认 0% / 无税。
config/中的国家预设提供的是税种标签、货币、付款方式、默认条款和编号前缀——绝不提供税率。config/bd.json(孟加拉国:৳,“VAT”,bKash / Nagad / Rocket / 银行转账 / 现金)和config/us.json(美国:$,“Sales tax”,Net 30)。两个配置文件中的tax_rate_percent故意设置为null。配置中的tax_id(你的 BIN)在输入未提供时填充于发票上。- 样本发票使用 15% VAT 是因为样本输入如此指定——孟加拉国在《2012 年增值税及附加税法》下的标准增值税税率为 15%(ArthiKalap,更新于 2026 年 7 月 25 日;TRW,2026-27 财年;TaxDo,2026 年;SDTT Academy,2026 年初)——但此技能并不知道这一点,且绝不能被视为知晓此事。VAT 申报再次变为 每季度一次(15 天内到期):《2026 年财政法案》曾使其自 2026 年 7 月 1 日起为季度申报,但 2026 年 10 月 14 日 公告的一项修正令恢复了每月申报(TRW“在孟加拉国经商 2026”,截至 2026 年 10 月 24 日的法律;entrepreneurs.bd,2026 年)。旧笔记中的任何“季度”行现在均为错误。
- 注册门槛未在此技能中硬编码。 三份独立的 2026 年 10–11 月指南现在趋同于相同数字——年营业额超过 Tk 50 万 需强制注册;年营业额 Tk 30–50 万 需注册并适用 4% 营业额税;某些活动无论营业额大小均需注册(TRW“孟加拉国增值税 2026”,截至 2026 年 10 月 18 日;TRW“增值税注册”;entrepreneurs.bd,2026 年;Aniday,2026 年 9 月验证)。但未能 直接获得 NBR 验证:NBR 首页(加载于 2026-11-11)未显示门槛文本,且 vat.gov.bd 当天无法访问。因此,这些数字在此作为 趋同的二手来源,非 NBR 验证的事实 报告——此技能绝不以自身之名陈述门槛,并引导用户访问 nbr.gov.bd。BIN 为 13 位(NBR 首页服务列表,2026-11-11——一个标签,非公报;在检查门槛时,请确认 NBR VAT 注册指南中的数字位数)。
- 支持含税价格:
"tax": {"name": "VAT", "rate_percent": 15, "inclusive": true}从总价中提取税费(VAT = 总价 × 15 ÷ 115)。已在MEASUREMENTS.md§5 中测量:৳1,150 总价 → ৳150 VAT,总计仍为 ৳1,150。
3. 支出记录——纯语言,纯文件
python3 scripts/bookkeeper.py expense add --ledger expenses.json --date 2026-11-11 --category Materials --amount 1200 --note "copper wire, 20 m"
python3 scripts/bookkeeper.py expense list --ledger expenses.json --month 2026-11
python3 scripts/bookkeeper.py expense export --ledger expenses.json --out expenses.csv
- 一条支出记录 = 日期、类别、金额、备注。分类账是一个 JSON 列表;
export写入一个可在任何电子表格软件中打开的 CSV 文件。 - 类别是纯语言,而非会计科目表:Materials、Transport、Tools、Mobile/internet、Meals、Rent、Labour、Packaging、Other。未知类别将报错,绝不静默接受。负数金额被拒绝。
--month必须是真实的YYYY-MM格式(2026-1被拒绝——原始前缀匹配会静默合并十月和十一月)。 - 分类账中一行若非对象,则会被大声跳过并发出警告且以 exit 2 退出——绝不回溯,绝不静默。
expense add拒绝覆写包含损坏行的分类账(需先修复)。
4. 超期跟踪器 + 催款草稿——此技能的核心
python3 scripts/bookkeeper.py overdue --invoices samples/invoices.json --as-of 2026-11-11
python3 scripts/bookkeeper.py overdue --invoices samples/invoices.json --as-of 2026-11-11 --lang bn --json
- 扫描发票分类账,按账龄区间(当前 / 1–30 / 31–60 / 61–90 / 90+ 天超期)列出每张未结发票,并为每张发票起草下一阶段的催款信。
- 6 阶段序列(Raoura 达成的 5 次联系共识,2026 年 7 月验证;InvoiceCub,2026 年 10 月 31 日;InvoiceFly,约 2026 年 11 月;HeroThemes,约 2026 年 8 月;FreelanceDesk,约 2026 年 6 月——到期前、到期日、逾期 7 天、14 天、30 天——再加上来自 7 次联系版本的逾期 1–6 天友好提醒;7 次联系版本中额外的 21 天联系不作为单独阶段,其范围由 14 天草稿的下一次联系(第 30 天)覆盖):到期前 3 天、到期日当天、逾期 7 天、逾期 14 天、逾期 30 天最终通知,另加逾期 1–6 天提醒。逐步升级,绝不先做指责:早期假设善意(忘记了 / 被埋没了 / 在审批队列中);仅当协议中约定了滞纳金且发票逾期约 2 周时才提及滞纳金。每份草稿均重述发票编号、金额、原始到期日——以及实际逾期天数(逾期 8 天的发票被告知“逾期 8 天”,而非阶段编号)。
- 仅草稿——此技能绝不发送任何内容。 你负责发送提醒。报表还打印下一次联系日期,因此升级不依赖于记忆。若下一次联系日期已过去,则打印为“立即发送(原应于……)”,绝不显示为单纯的过去日期。最终通知给出一个最早自今天起 7 天后的截止日期(
max(due + 37 days, as-of + 7 days))——一个截止日期已过去的催款比没有更糟。 - 基于样本(截至 2026-11-11)测量:6 张未结发票,他人欠你 ৳48,650(বাকি),4 张超期,总计 ৳28,250——每张处于从提醒到最终通知的不同阶段。见
MEASUREMENTS.md§3。 - 草稿发票被排除在“他人欠你”之外——未发送的发票尚非所欠款项。已付发票(余额为 0)也被排除。(跟进 100% 超期发票的企业在一周内被付款的可能性高 76%——Chaser 2026 AR 报告,引自 Raoura,二手资料。)
5. 简单的现金流视图——企业主实际核对的数字
python3 scripts/bookkeeper.py cashflow --invoices samples/invoices.json --expenses samples/expenses.json --as-of 2026-11-11
- 在一个屏幕上显示本月收入、支出、以及他人欠你的款项。报告期始终是当前月份:从
as-of所在月的第一天到as-of当天。在上个月运行cashflow?你不会收到上个月的数字;报告会比较:2026-10-11会显示该月 1 日到 11 日的部分月份情况,并在月份标题中标注“至今日”。已提交的发票包括在内(如果余额非零,它代表在催收的欠款——零余额意味着已结清并移除,因为收讫)。已付发票仍属于本月已实现收入——报告说“本月已实现收入 ৳X”,并且(分开的)超期未付 ৳Y。税率在现金流视图中被扣除:总金额减去计算出的税费(正确的方式——税费不由你保留)。条目与标准报告一致:卖出物品的支票银行账户、提取现金的账单、银行收取的费用、未付发票、以及始终追踪的最惊人的一个——未领工资/业主提款。分类账要求与overdue完全相同的严格性——exit 2 表示分类账需先修复。混合币种显示为拆分总计。
文件结构
smb-bookkeeper/
├── config/ # 国家预设(BD、US)——标签、货币、付款方式,绝无税率
├── samples/ # 示例 JSON 文件(发票、分类账)
├── scripts/
│ ├── bookkeeper.py # 主 CLI 入口
│ ├── invoice.py # 发票/报价单/收据生成
│ ├── expense.py # 支出记录
│ ├── overdue.py # 超期跟踪 + 催款起草
│ ├── cashflow.py # 现金流视图
│ └── views/ # HTML/Markdown 模板
├── docs/ # 截图、示例 PDF
├── MEASUREMENTS.md # 样本输出和测量
├── CHANGELOG.md # 变更日志
└── research-notes/ # 发票和催款实践的研究笔记
支持和许可
- 请使用
--help探索命令:python3 scripts/bookkeeper.py --help。 - 此技能根据 MIT 许可发布。
- 问题、功能请求或 BIN 验证结果?请在此 GitHub 仓库中打开一个问题。
- 需要更深入的簿记参考,请参见 OpenAccountants 的
bd-bookkeeping技能(英文,非发票生成)。